]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/config/score/score.c
6d81cd60901422fff4e8024e8a67d36068e0df5b
[thirdparty/gcc.git] / gcc / config / score / score.c
1 /* Output routines for Sunplus S+CORE processor
2 Copyright (C) 2005, 2007, 2008, 2009, 2010, 2011
3 Free Software Foundation, Inc.
4 Contributed by Sunnorth.
5
6 This file is part of GCC.
7
8 GCC is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published
10 by the Free Software Foundation; either version 3, or (at your
11 option) any later version.
12
13 GCC is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
21
22 #include "config.h"
23 #include "system.h"
24 #include "coretypes.h"
25 #include "tm.h"
26 #include "rtl.h"
27 #include "regs.h"
28 #include "hard-reg-set.h"
29 #include "insn-config.h"
30 #include "conditions.h"
31 #include "insn-attr.h"
32 #include "recog.h"
33 #include "diagnostic-core.h"
34 #include "output.h"
35 #include "tree.h"
36 #include "function.h"
37 #include "expr.h"
38 #include "optabs.h"
39 #include "flags.h"
40 #include "reload.h"
41 #include "tm_p.h"
42 #include "ggc.h"
43 #include "gstab.h"
44 #include "hashtab.h"
45 #include "debug.h"
46 #include "target.h"
47 #include "target-def.h"
48 #include "langhooks.h"
49 #include "df.h"
50 #include "opts.h"
51
52 #define SCORE_SDATA_MAX score_sdata_max
53 #define SCORE_STACK_ALIGN(LOC) (((LOC) + 3) & ~3)
54 #define SCORE_PROLOGUE_TEMP_REGNUM (GP_REG_FIRST + 8)
55 #define SCORE_EPILOGUE_TEMP_REGNUM (GP_REG_FIRST + 8)
56 #define SCORE_DEFAULT_SDATA_MAX 8
57
58 #define BITSET_P(VALUE, BIT) (((VALUE) & (1L << (BIT))) != 0)
59 #define INS_BUF_SZ 128
60
61 enum score_address_type
62 {
63 SCORE_ADD_REG,
64 SCORE_ADD_CONST_INT,
65 SCORE_ADD_SYMBOLIC
66 };
67
68 struct score_frame_info
69 {
70 HOST_WIDE_INT total_size; /* bytes that the entire frame takes up */
71 HOST_WIDE_INT var_size; /* bytes that variables take up */
72 HOST_WIDE_INT args_size; /* bytes that outgoing arguments take up */
73 HOST_WIDE_INT gp_reg_size; /* bytes needed to store gp regs */
74 HOST_WIDE_INT gp_sp_offset; /* offset from new sp to store gp registers */
75 HOST_WIDE_INT cprestore_size; /* # bytes that the .cprestore slot takes up */
76 unsigned int mask; /* mask of saved gp registers */
77 int num_gp; /* number of gp registers saved */
78 };
79
80 struct score_arg_info
81 {
82 unsigned int num_bytes; /* The argument's size in bytes */
83 unsigned int reg_words; /* The number of words passed in registers */
84 unsigned int reg_offset; /* The offset of the first register from */
85 /* GP_ARG_FIRST or FP_ARG_FIRST etc */
86 unsigned int stack_words; /* The number of words that must be passed */
87 /* on the stack */
88 unsigned int stack_offset; /* The offset from the start of the stack */
89 /* overflow area */
90 };
91
92 #ifdef RTX_CODE
93 struct score_address_info
94 {
95 enum score_address_type type;
96 rtx reg;
97 rtx offset;
98 enum rtx_code code;
99 enum score_symbol_type symbol_type;
100 };
101 #endif
102
103 static int score_sdata_max;
104 static char score_ins[INS_BUF_SZ + 8];
105
106 struct extern_list *extern_head = 0;
107
108 #undef TARGET_ASM_FILE_START
109 #define TARGET_ASM_FILE_START score_asm_file_start
110
111 #undef TARGET_ASM_FILE_END
112 #define TARGET_ASM_FILE_END score_asm_file_end
113
114 #undef TARGET_ASM_FUNCTION_PROLOGUE
115 #define TARGET_ASM_FUNCTION_PROLOGUE score_function_prologue
116
117 #undef TARGET_ASM_FUNCTION_EPILOGUE
118 #define TARGET_ASM_FUNCTION_EPILOGUE score_function_epilogue
119
120 #undef TARGET_OPTION_OVERRIDE
121 #define TARGET_OPTION_OVERRIDE score_option_override
122
123 #undef TARGET_LEGITIMIZE_ADDRESS
124 #define TARGET_LEGITIMIZE_ADDRESS score_legitimize_address
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 insn_locators_alloc ();
509 split_all_insns_noflow ();
510 shorten_branches (insn);
511 final_start_function (insn, file, 1);
512 final (insn, file, 1);
513 final_end_function ();
514
515 /* Clean up the vars set above. Note that final_end_function resets
516 the global pointer for us. */
517 reload_completed = 0;
518 }
519
520 /* Copy VALUE to a register and return that register. If new psuedos
521 are allowed, copy it into a new register, otherwise use DEST. */
522 static rtx
523 score_force_temporary (rtx dest, rtx value)
524 {
525 if (can_create_pseudo_p ())
526 return force_reg (Pmode, value);
527 else
528 {
529 emit_move_insn (copy_rtx (dest), value);
530 return dest;
531 }
532 }
533
534 /* Return a LO_SUM expression for ADDR. TEMP is as for score_force_temporary
535 and is used to load the high part into a register. */
536 static rtx
537 score_split_symbol (rtx temp, rtx addr)
538 {
539 rtx high = score_force_temporary (temp,
540 gen_rtx_HIGH (Pmode, copy_rtx (addr)));
541 return gen_rtx_LO_SUM (Pmode, high, addr);
542 }
543
544 /* This function is used to implement LEGITIMIZE_ADDRESS. If X can
545 be legitimized in a way that the generic machinery might not expect,
546 return the new address. */
547 static rtx
548 score_legitimize_address (rtx x)
549 {
550 enum score_symbol_type symbol_type;
551
552 if (score_symbolic_constant_p (x, &symbol_type)
553 && symbol_type == SYMBOL_GENERAL)
554 return score_split_symbol (0, x);
555
556 if (GET_CODE (x) == PLUS
557 && GET_CODE (XEXP (x, 1)) == CONST_INT)
558 {
559 rtx reg = XEXP (x, 0);
560 if (!score_valid_base_register_p (reg, 0))
561 reg = copy_to_mode_reg (Pmode, reg);
562 return score_add_offset (reg, INTVAL (XEXP (x, 1)));
563 }
564
565 return x;
566 }
567
568 /* Fill INFO with information about a single argument. CUM is the
569 cumulative state for earlier arguments. MODE is the mode of this
570 argument and TYPE is its type (if known). NAMED is true if this
571 is a named (fixed) argument rather than a variable one. */
572 static void
573 score_classify_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
574 const_tree type, bool named, struct score_arg_info *info)
575 {
576 int even_reg_p;
577 unsigned int num_words, max_regs;
578
579 even_reg_p = 0;
580 if (GET_MODE_CLASS (mode) == MODE_INT
581 || GET_MODE_CLASS (mode) == MODE_FLOAT)
582 even_reg_p = (GET_MODE_SIZE (mode) > UNITS_PER_WORD);
583 else
584 if (type != NULL_TREE && TYPE_ALIGN (type) > BITS_PER_WORD && named)
585 even_reg_p = 1;
586
587 if (TARGET_MUST_PASS_IN_STACK (mode, type))
588 info->reg_offset = ARG_REG_NUM;
589 else
590 {
591 info->reg_offset = cum->num_gprs;
592 if (even_reg_p)
593 info->reg_offset += info->reg_offset & 1;
594 }
595
596 if (mode == BLKmode)
597 info->num_bytes = int_size_in_bytes (type);
598 else
599 info->num_bytes = GET_MODE_SIZE (mode);
600
601 num_words = (info->num_bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
602 max_regs = ARG_REG_NUM - info->reg_offset;
603
604 /* Partition the argument between registers and stack. */
605 info->reg_words = MIN (num_words, max_regs);
606 info->stack_words = num_words - info->reg_words;
607
608 /* The alignment applied to registers is also applied to stack arguments. */
609 if (info->stack_words)
610 {
611 info->stack_offset = cum->stack_words;
612 if (even_reg_p)
613 info->stack_offset += info->stack_offset & 1;
614 }
615 }
616
617 /* Set up the stack and frame (if desired) for the function. */
618 static void
619 score_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
620 {
621 const char *fnname;
622 struct score_frame_info *f = score_cached_frame ();
623 HOST_WIDE_INT tsize = f->total_size;
624
625 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
626 if (!flag_inhibit_size_directive)
627 {
628 fputs ("\t.ent\t", file);
629 assemble_name (file, fnname);
630 fputs ("\n", file);
631 }
632 assemble_name (file, fnname);
633 fputs (":\n", file);
634
635 if (!flag_inhibit_size_directive)
636 {
637 fprintf (file,
638 "\t.frame\t%s," HOST_WIDE_INT_PRINT_DEC ",%s, %d\t\t"
639 "# vars= " HOST_WIDE_INT_PRINT_DEC ", regs= %d"
640 ", args= " HOST_WIDE_INT_PRINT_DEC
641 ", gp= " HOST_WIDE_INT_PRINT_DEC "\n",
642 (reg_names[(frame_pointer_needed)
643 ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM]),
644 tsize,
645 reg_names[RA_REGNUM],
646 crtl->is_leaf ? 1 : 0,
647 f->var_size,
648 f->num_gp,
649 f->args_size,
650 f->cprestore_size);
651
652 fprintf(file, "\t.mask\t0x%08x," HOST_WIDE_INT_PRINT_DEC "\n",
653 f->mask,
654 (f->gp_sp_offset - f->total_size));
655 }
656 }
657
658 /* Do any necessary cleanup after a function to restore stack, frame,
659 and regs. */
660 static void
661 score_function_epilogue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
662 {
663 if (!flag_inhibit_size_directive)
664 {
665 const char *fnname;
666 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
667 fputs ("\t.end\t", file);
668 assemble_name (file, fnname);
669 fputs ("\n", file);
670 }
671 }
672
673 /* Returns true if X contains a SYMBOL_REF. */
674 static bool
675 score_symbolic_expression_p (rtx x)
676 {
677 if (GET_CODE (x) == SYMBOL_REF)
678 return true;
679
680 if (GET_CODE (x) == CONST)
681 return score_symbolic_expression_p (XEXP (x, 0));
682
683 if (UNARY_P (x))
684 return score_symbolic_expression_p (XEXP (x, 0));
685
686 if (ARITHMETIC_P (x))
687 return (score_symbolic_expression_p (XEXP (x, 0))
688 || score_symbolic_expression_p (XEXP (x, 1)));
689
690 return false;
691 }
692
693 /* Choose the section to use for the constant rtx expression X that has
694 mode MODE. */
695 static section *
696 score_select_rtx_section (enum machine_mode mode, rtx x, unsigned HOST_WIDE_INT align)
697 {
698 if (GET_MODE_SIZE (mode) <= SCORE_SDATA_MAX)
699 return get_named_section (0, ".sdata", 0);
700 else if (flag_pic && score_symbolic_expression_p (x))
701 return get_named_section (0, ".data.rel.ro", 3);
702 else
703 return mergeable_constant_section (mode, align, 0);
704 }
705
706 /* Implement TARGET_IN_SMALL_DATA_P. */
707 static bool
708 score_in_small_data_p (const_tree decl)
709 {
710 HOST_WIDE_INT size;
711
712 if (TREE_CODE (decl) == STRING_CST
713 || TREE_CODE (decl) == FUNCTION_DECL)
714 return false;
715
716 if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl) != 0)
717 {
718 const char *name;
719 name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
720 if (strcmp (name, ".sdata") != 0
721 && strcmp (name, ".sbss") != 0)
722 return true;
723 if (!DECL_EXTERNAL (decl))
724 return false;
725 }
726 size = int_size_in_bytes (TREE_TYPE (decl));
727 return (size > 0 && size <= SCORE_SDATA_MAX);
728 }
729
730 /* Implement TARGET_ASM_FILE_START. */
731 static void
732 score_asm_file_start (void)
733 {
734 default_file_start ();
735 fprintf (asm_out_file, ASM_COMMENT_START
736 "GCC for S+core %s \n", SCORE_GCC_VERSION);
737
738 if (flag_pic)
739 fprintf (asm_out_file, "\t.set pic\n");
740 }
741
742 /* Implement TARGET_ASM_FILE_END. When using assembler macros, emit
743 .externs for any small-data variables that turned out to be external. */
744 static void
745 score_asm_file_end (void)
746 {
747 tree name_tree;
748 struct extern_list *p;
749 if (extern_head)
750 {
751 fputs ("\n", asm_out_file);
752 for (p = extern_head; p != 0; p = p->next)
753 {
754 name_tree = get_identifier (p->name);
755 if (!TREE_ASM_WRITTEN (name_tree)
756 && TREE_SYMBOL_REFERENCED (name_tree))
757 {
758 TREE_ASM_WRITTEN (name_tree) = 1;
759 fputs ("\t.extern\t", asm_out_file);
760 assemble_name (asm_out_file, p->name);
761 fprintf (asm_out_file, ", %d\n", p->size);
762 }
763 }
764 }
765 }
766
767 /* Implement TARGET_OPTION_OVERRIDE hook. */
768 static void
769 score_option_override (void)
770 {
771 flag_pic = false;
772 score_sdata_max = SCORE_DEFAULT_SDATA_MAX;
773
774 }
775
776 /* Implement REGNO_REG_CLASS macro. */
777 int
778 score_reg_class (int regno)
779 {
780 int c;
781 gcc_assert (regno >= 0 && regno < FIRST_PSEUDO_REGISTER);
782
783 if (regno == FRAME_POINTER_REGNUM
784 || regno == ARG_POINTER_REGNUM)
785 return ALL_REGS;
786
787 for (c = 0; c < N_REG_CLASSES; c++)
788 if (TEST_HARD_REG_BIT (reg_class_contents[c], regno))
789 return c;
790
791 return NO_REGS;
792 }
793
794 /* Implement PREFERRED_RELOAD_CLASS macro. */
795 enum reg_class
796 score_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class rclass)
797 {
798 if (reg_class_subset_p (G16_REGS, rclass))
799 return G16_REGS;
800 if (reg_class_subset_p (G32_REGS, rclass))
801 return G32_REGS;
802 return rclass;
803 }
804
805 /* Implement SECONDARY_INPUT_RELOAD_CLASS
806 and SECONDARY_OUTPUT_RELOAD_CLASS macro. */
807 enum reg_class
808 score_secondary_reload_class (enum reg_class rclass,
809 enum machine_mode mode ATTRIBUTE_UNUSED,
810 rtx x)
811 {
812 int regno = -1;
813 if (GET_CODE (x) == REG || GET_CODE(x) == SUBREG)
814 regno = true_regnum (x);
815
816 if (!GR_REG_CLASS_P (rclass))
817 return GP_REG_P (regno) ? NO_REGS : G32_REGS;
818 return NO_REGS;
819 }
820
821
822 /* Return truth value on whether or not a given hard register
823 can support a given mode. */
824 int
825 score_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
826 {
827 int size = GET_MODE_SIZE (mode);
828 enum mode_class mclass = GET_MODE_CLASS (mode);
829
830 if (mclass == MODE_CC)
831 return regno == CC_REGNUM;
832 else if (regno == FRAME_POINTER_REGNUM
833 || regno == ARG_POINTER_REGNUM)
834 return mclass == MODE_INT;
835 else if (GP_REG_P (regno))
836 /* ((regno <= (GP_REG_LAST- HARD_REGNO_NREGS (dummy, mode)) + 1) */
837 return !(regno & 1) || (size <= UNITS_PER_WORD);
838 else if (CE_REG_P (regno))
839 return (mclass == MODE_INT
840 && ((size <= UNITS_PER_WORD)
841 || (regno == CE_REG_FIRST && size == 2 * UNITS_PER_WORD)));
842 else
843 return (mclass == MODE_INT) && (size <= UNITS_PER_WORD);
844 }
845
846 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
847 pointer or argument pointer. TO is either the stack pointer or
848 hard frame pointer. */
849 HOST_WIDE_INT
850 score_initial_elimination_offset (int from,
851 int to ATTRIBUTE_UNUSED)
852 {
853 struct score_frame_info *f = score_compute_frame_size (get_frame_size ());
854 switch (from)
855 {
856 case ARG_POINTER_REGNUM:
857 return f->total_size;
858 case FRAME_POINTER_REGNUM:
859 return 0;
860 default:
861 gcc_unreachable ();
862 }
863 }
864
865 /* Implement TARGET_FUNCTION_ARG_ADVANCE hook. */
866 static void
867 score_function_arg_advance (cumulative_args_t cum_args, enum machine_mode mode,
868 const_tree type, bool named)
869 {
870 struct score_arg_info info;
871 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_args);
872 score_classify_arg (cum, mode, type, named, &info);
873 cum->num_gprs = info.reg_offset + info.reg_words;
874 if (info.stack_words > 0)
875 cum->stack_words = info.stack_offset + info.stack_words;
876 cum->arg_number++;
877 }
878
879 /* Implement TARGET_ARG_PARTIAL_BYTES macro. */
880 int
881 score_arg_partial_bytes (cumulative_args_t cum_args,
882 enum machine_mode mode, tree type, bool named)
883 {
884 struct score_arg_info info;
885 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_args);
886 score_classify_arg (cum, mode, type, named, &info);
887 return info.stack_words > 0 ? info.reg_words * UNITS_PER_WORD : 0;
888 }
889
890 /* Implement TARGET_FUNCTION_ARG hook. */
891 static rtx
892 score_function_arg (cumulative_args_t cum_args, enum machine_mode mode,
893 const_tree type, bool named)
894 {
895 struct score_arg_info info;
896 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_args);
897
898 if (mode == VOIDmode || !named)
899 return 0;
900
901 score_classify_arg (cum, mode, type, named, &info);
902
903 if (info.reg_offset == ARG_REG_NUM)
904 return 0;
905
906 if (!info.stack_words)
907 return gen_rtx_REG (mode, ARG_REG_FIRST + info.reg_offset);
908 else
909 {
910 rtx ret = gen_rtx_PARALLEL (mode, rtvec_alloc (info.reg_words));
911 unsigned int i, part_offset = 0;
912 for (i = 0; i < info.reg_words; i++)
913 {
914 rtx reg;
915 reg = gen_rtx_REG (SImode, ARG_REG_FIRST + info.reg_offset + i);
916 XVECEXP (ret, 0, i) = gen_rtx_EXPR_LIST (SImode, reg,
917 GEN_INT (part_offset));
918 part_offset += UNITS_PER_WORD;
919 }
920 return ret;
921 }
922 }
923
924 /* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls,
925 VALTYPE is the return type and MODE is VOIDmode. For libcalls,
926 VALTYPE is null and MODE is the mode of the return value. */
927 rtx
928 score_function_value (const_tree valtype, const_tree func, enum machine_mode mode)
929 {
930 if (valtype)
931 {
932 int unsignedp;
933 mode = TYPE_MODE (valtype);
934 unsignedp = TYPE_UNSIGNED (valtype);
935 mode = promote_function_mode (valtype, mode, &unsignedp, func, 1);
936 }
937 return gen_rtx_REG (mode, RT_REGNUM);
938 }
939
940 /* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */
941
942 static void
943 score_asm_trampoline_template (FILE *f)
944 {
945 fprintf (f, "\t.set r1\n");
946 fprintf (f, "\tmv r31, r3\n");
947 fprintf (f, "\tbl nextinsn\n");
948 fprintf (f, "nextinsn:\n");
949 fprintf (f, "\tlw r1, [r3, 6*4-8]\n");
950 fprintf (f, "\tlw r23, [r3, 6*4-4]\n");
951 fprintf (f, "\tmv r3, r31\n");
952 fprintf (f, "\tbr! r1\n");
953 fprintf (f, "\tnop!\n");
954 fprintf (f, "\t.set nor1\n");
955 }
956
957 /* Implement TARGET_TRAMPOLINE_INIT. */
958 static void
959 score_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
960 {
961 #define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD)
962
963 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
964 rtx mem;
965
966 emit_block_move (m_tramp, assemble_trampoline_template (),
967 GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
968
969 mem = adjust_address (m_tramp, SImode, CODE_SIZE);
970 emit_move_insn (mem, fnaddr);
971 mem = adjust_address (m_tramp, SImode, CODE_SIZE + GET_MODE_SIZE (SImode));
972 emit_move_insn (mem, chain_value);
973
974 #undef CODE_SIZE
975 }
976
977 /* This function is used to implement REG_MODE_OK_FOR_BASE_P macro. */
978 int
979 score_regno_mode_ok_for_base_p (int regno, int strict)
980 {
981 if (regno >= FIRST_PSEUDO_REGISTER)
982 {
983 if (!strict)
984 return 1;
985 regno = reg_renumber[regno];
986 }
987 if (regno == ARG_POINTER_REGNUM
988 || regno == FRAME_POINTER_REGNUM)
989 return 1;
990 return GP_REG_P (regno);
991 }
992
993 /* Implement TARGET_LEGITIMATE_ADDRESS_P macro. */
994 static bool
995 score_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
996 {
997 struct score_address_info addr;
998
999 return score_classify_address (&addr, mode, x, strict);
1000 }
1001
1002 /* Implement TARGET_REGISTER_MOVE_COST.
1003
1004 Return a number assessing the cost of moving a register in class
1005 FROM to class TO. */
1006 static int
1007 score_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
1008 reg_class_t from, reg_class_t to)
1009 {
1010 if (GR_REG_CLASS_P (from))
1011 {
1012 if (GR_REG_CLASS_P (to))
1013 return 2;
1014 else if (SP_REG_CLASS_P (to))
1015 return 4;
1016 else if (CP_REG_CLASS_P (to))
1017 return 5;
1018 else if (CE_REG_CLASS_P (to))
1019 return 6;
1020 }
1021 if (GR_REG_CLASS_P (to))
1022 {
1023 if (GR_REG_CLASS_P (from))
1024 return 2;
1025 else if (SP_REG_CLASS_P (from))
1026 return 4;
1027 else if (CP_REG_CLASS_P (from))
1028 return 5;
1029 else if (CE_REG_CLASS_P (from))
1030 return 6;
1031 }
1032 return 12;
1033 }
1034
1035 /* Return the number of instructions needed to load a symbol of the
1036 given type into a register. */
1037 static int
1038 score_symbol_insns (enum score_symbol_type type)
1039 {
1040 switch (type)
1041 {
1042 case SYMBOL_GENERAL:
1043 return 2;
1044
1045 case SYMBOL_SMALL_DATA:
1046 return 1;
1047 }
1048
1049 gcc_unreachable ();
1050 }
1051
1052 /* Return the number of instructions needed to load or store a value
1053 of mode MODE at X. Return 0 if X isn't valid for MODE. */
1054 static int
1055 score_address_insns (rtx x, enum machine_mode mode)
1056 {
1057 struct score_address_info addr;
1058 int factor;
1059
1060 if (mode == BLKmode)
1061 factor = 1;
1062 else
1063 factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1064
1065 if (score_classify_address (&addr, mode, x, false))
1066 switch (addr.type)
1067 {
1068 case SCORE_ADD_REG:
1069 case SCORE_ADD_CONST_INT:
1070 return factor;
1071
1072 case SCORE_ADD_SYMBOLIC:
1073 return factor * score_symbol_insns (addr.symbol_type);
1074 }
1075 return 0;
1076 }
1077
1078 /* Implement TARGET_RTX_COSTS macro. */
1079 bool
1080 score_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
1081 int *total, bool speed ATTRIBUTE_UNUSED)
1082 {
1083 enum machine_mode mode = GET_MODE (x);
1084
1085 switch (code)
1086 {
1087 case CONST_INT:
1088 if (outer_code == SET)
1089 {
1090 if (((INTVAL (x) & 0xffff) == 0)
1091 || (INTVAL (x) >= -32768 && INTVAL (x) <= 32767))
1092 *total = COSTS_N_INSNS (1);
1093 else
1094 *total = COSTS_N_INSNS (2);
1095 }
1096 else if (outer_code == PLUS || outer_code == MINUS)
1097 {
1098 if (INTVAL (x) >= -8192 && INTVAL (x) <= 8191)
1099 *total = 0;
1100 else if (((INTVAL (x) & 0xffff) == 0)
1101 || (INTVAL (x) >= -32768 && INTVAL (x) <= 32767))
1102 *total = 1;
1103 else
1104 *total = COSTS_N_INSNS (2);
1105 }
1106 else if (outer_code == AND || outer_code == IOR)
1107 {
1108 if (INTVAL (x) >= 0 && INTVAL (x) <= 16383)
1109 *total = 0;
1110 else if (((INTVAL (x) & 0xffff) == 0)
1111 || (INTVAL (x) >= 0 && INTVAL (x) <= 65535))
1112 *total = 1;
1113 else
1114 *total = COSTS_N_INSNS (2);
1115 }
1116 else
1117 {
1118 *total = 0;
1119 }
1120 return true;
1121
1122 case CONST:
1123 case SYMBOL_REF:
1124 case LABEL_REF:
1125 case CONST_DOUBLE:
1126 *total = COSTS_N_INSNS (2);
1127 return true;
1128
1129 case MEM:
1130 {
1131 /* If the address is legitimate, return the number of
1132 instructions it needs, otherwise use the default handling. */
1133 int n = score_address_insns (XEXP (x, 0), GET_MODE (x));
1134 if (n > 0)
1135 {
1136 *total = COSTS_N_INSNS (n + 1);
1137 return true;
1138 }
1139 return false;
1140 }
1141
1142 case FFS:
1143 *total = COSTS_N_INSNS (6);
1144 return true;
1145
1146 case NOT:
1147 *total = COSTS_N_INSNS (1);
1148 return true;
1149
1150 case AND:
1151 case IOR:
1152 case XOR:
1153 if (mode == DImode)
1154 {
1155 *total = COSTS_N_INSNS (2);
1156 return true;
1157 }
1158 return false;
1159
1160 case ASHIFT:
1161 case ASHIFTRT:
1162 case LSHIFTRT:
1163 if (mode == DImode)
1164 {
1165 *total = COSTS_N_INSNS ((GET_CODE (XEXP (x, 1)) == CONST_INT)
1166 ? 4 : 12);
1167 return true;
1168 }
1169 return false;
1170
1171 case ABS:
1172 *total = COSTS_N_INSNS (4);
1173 return true;
1174
1175 case PLUS:
1176 case MINUS:
1177 if (mode == DImode)
1178 {
1179 *total = COSTS_N_INSNS (4);
1180 return true;
1181 }
1182 *total = COSTS_N_INSNS (1);
1183 return true;
1184
1185 case NEG:
1186 if (mode == DImode)
1187 {
1188 *total = COSTS_N_INSNS (4);
1189 return true;
1190 }
1191 return false;
1192
1193 case MULT:
1194 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (12);
1195 return true;
1196
1197 case DIV:
1198 case MOD:
1199 case UDIV:
1200 case UMOD:
1201 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (33);
1202 return true;
1203
1204 case SIGN_EXTEND:
1205 case ZERO_EXTEND:
1206 switch (GET_MODE (XEXP (x, 0)))
1207 {
1208 case QImode:
1209 case HImode:
1210 if (GET_CODE (XEXP (x, 0)) == MEM)
1211 {
1212 *total = COSTS_N_INSNS (2);
1213
1214 if (!TARGET_LITTLE_ENDIAN &&
1215 side_effects_p (XEXP (XEXP (x, 0), 0)))
1216 *total = 100;
1217 }
1218 else
1219 *total = COSTS_N_INSNS (1);
1220 break;
1221
1222 default:
1223 *total = COSTS_N_INSNS (1);
1224 break;
1225 }
1226 return true;
1227
1228 default:
1229 return false;
1230 }
1231 }
1232
1233 /* Implement TARGET_ADDRESS_COST macro. */
1234 int
1235 score_address_cost (rtx addr,
1236 bool speed ATTRIBUTE_UNUSED)
1237 {
1238 return score_address_insns (addr, SImode);
1239 }
1240
1241 /* Implement ASM_OUTPUT_EXTERNAL macro. */
1242 int
1243 score_output_external (FILE *file ATTRIBUTE_UNUSED,
1244 tree decl, const char *name)
1245 {
1246 register struct extern_list *p;
1247
1248 if (score_in_small_data_p (decl))
1249 {
1250 p = ggc_alloc_extern_list ();
1251 p->next = extern_head;
1252 p->name = name;
1253 p->size = int_size_in_bytes (TREE_TYPE (decl));
1254 extern_head = p;
1255 }
1256 return 0;
1257 }
1258
1259 /* Implement RETURN_ADDR_RTX. Note, we do not support moving
1260 back to a previous frame. */
1261 rtx
1262 score_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
1263 {
1264 if (count != 0)
1265 return const0_rtx;
1266 return get_hard_reg_initial_val (Pmode, RA_REGNUM);
1267 }
1268
1269 /* Implement PRINT_OPERAND macro. */
1270 /* Score-specific operand codes:
1271 '[' print .set nor1 directive
1272 ']' print .set r1 directive
1273 'U' print hi part of a CONST_INT rtx
1274 'E' print log2(v)
1275 'F' print log2(~v)
1276 'D' print SFmode const double
1277 'S' selectively print "!" if operand is 15bit instruction accessible
1278 'V' print "v!" if operand is 15bit instruction accessible, or "lfh!"
1279 'L' low part of DImode reg operand
1280 'H' high part of DImode reg operand
1281 'C' print part of opcode for a branch condition. */
1282 void
1283 score_print_operand (FILE *file, rtx op, int c)
1284 {
1285 enum rtx_code code = UNKNOWN;
1286 if (!PRINT_OPERAND_PUNCT_VALID_P (c))
1287 code = GET_CODE (op);
1288
1289 if (c == '[')
1290 {
1291 fprintf (file, ".set r1\n");
1292 }
1293 else if (c == ']')
1294 {
1295 fprintf (file, "\n\t.set nor1");
1296 }
1297 else if (c == 'U')
1298 {
1299 gcc_assert (code == CONST_INT);
1300 fprintf (file, HOST_WIDE_INT_PRINT_HEX,
1301 (INTVAL (op) >> 16) & 0xffff);
1302 }
1303 else if (c == 'D')
1304 {
1305 if (GET_CODE (op) == CONST_DOUBLE)
1306 {
1307 rtx temp = gen_lowpart (SImode, op);
1308 gcc_assert (GET_MODE (op) == SFmode);
1309 fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (temp) & 0xffffffff);
1310 }
1311 else
1312 output_addr_const (file, op);
1313 }
1314 else if (c == 'S')
1315 {
1316 gcc_assert (code == REG);
1317 if (G16_REG_P (REGNO (op)))
1318 fprintf (file, "!");
1319 }
1320 else if (c == 'V')
1321 {
1322 gcc_assert (code == REG);
1323 fprintf (file, G16_REG_P (REGNO (op)) ? "v!" : "lfh!");
1324 }
1325 else if (c == 'C')
1326 {
1327 enum machine_mode mode = GET_MODE (XEXP (op, 0));
1328
1329 switch (code)
1330 {
1331 case EQ: fputs ("eq", file); break;
1332 case NE: fputs ("ne", file); break;
1333 case GT: fputs ("gt", file); break;
1334 case GE: fputs (mode != CCmode ? "pl" : "ge", file); break;
1335 case LT: fputs (mode != CCmode ? "mi" : "lt", file); break;
1336 case LE: fputs ("le", file); break;
1337 case GTU: fputs ("gtu", file); break;
1338 case GEU: fputs ("cs", file); break;
1339 case LTU: fputs ("cc", file); break;
1340 case LEU: fputs ("leu", file); break;
1341 default:
1342 output_operand_lossage ("invalid operand for code: '%c'", code);
1343 }
1344 }
1345 else if (c == 'E')
1346 {
1347 unsigned HOST_WIDE_INT i;
1348 unsigned HOST_WIDE_INT pow2mask = 1;
1349 unsigned HOST_WIDE_INT val;
1350
1351 val = INTVAL (op);
1352 for (i = 0; i < 32; i++)
1353 {
1354 if (val == pow2mask)
1355 break;
1356 pow2mask <<= 1;
1357 }
1358 gcc_assert (i < 32);
1359 fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1360 }
1361 else if (c == 'F')
1362 {
1363 unsigned HOST_WIDE_INT i;
1364 unsigned HOST_WIDE_INT pow2mask = 1;
1365 unsigned HOST_WIDE_INT val;
1366
1367 val = ~INTVAL (op);
1368 for (i = 0; i < 32; i++)
1369 {
1370 if (val == pow2mask)
1371 break;
1372 pow2mask <<= 1;
1373 }
1374 gcc_assert (i < 32);
1375 fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1376 }
1377 else if (code == REG)
1378 {
1379 int regnum = REGNO (op);
1380 if ((c == 'H' && !WORDS_BIG_ENDIAN)
1381 || (c == 'L' && WORDS_BIG_ENDIAN))
1382 regnum ++;
1383 fprintf (file, "%s", reg_names[regnum]);
1384 }
1385 else
1386 {
1387 switch (code)
1388 {
1389 case MEM:
1390 score_print_operand_address (file, op);
1391 break;
1392 default:
1393 output_addr_const (file, op);
1394 }
1395 }
1396 }
1397
1398 /* Implement PRINT_OPERAND_ADDRESS macro. */
1399 void
1400 score_print_operand_address (FILE *file, rtx x)
1401 {
1402 struct score_address_info addr;
1403 enum rtx_code code = GET_CODE (x);
1404 enum machine_mode mode = GET_MODE (x);
1405
1406 if (code == MEM)
1407 x = XEXP (x, 0);
1408
1409 if (score_classify_address (&addr, mode, x, true))
1410 {
1411 switch (addr.type)
1412 {
1413 case SCORE_ADD_REG:
1414 {
1415 switch (addr.code)
1416 {
1417 case PRE_DEC:
1418 fprintf (file, "[%s,-%ld]+", reg_names[REGNO (addr.reg)],
1419 INTVAL (addr.offset));
1420 break;
1421 case POST_DEC:
1422 fprintf (file, "[%s]+,-%ld", reg_names[REGNO (addr.reg)],
1423 INTVAL (addr.offset));
1424 break;
1425 case PRE_INC:
1426 fprintf (file, "[%s, %ld]+", reg_names[REGNO (addr.reg)],
1427 INTVAL (addr.offset));
1428 break;
1429 case POST_INC:
1430 fprintf (file, "[%s]+, %ld", reg_names[REGNO (addr.reg)],
1431 INTVAL (addr.offset));
1432 break;
1433 default:
1434 if (INTVAL(addr.offset) == 0)
1435 fprintf(file, "[%s]", reg_names[REGNO (addr.reg)]);
1436 else
1437 fprintf(file, "[%s, %ld]", reg_names[REGNO (addr.reg)],
1438 INTVAL(addr.offset));
1439 break;
1440 }
1441 }
1442 return;
1443 case SCORE_ADD_CONST_INT:
1444 case SCORE_ADD_SYMBOLIC:
1445 output_addr_const (file, x);
1446 return;
1447 }
1448 }
1449 print_rtl (stderr, x);
1450 gcc_unreachable ();
1451 }
1452
1453 /* Implement SELECT_CC_MODE macro. */
1454 enum machine_mode
1455 score_select_cc_mode (enum rtx_code op, rtx x, rtx y)
1456 {
1457 if ((op == EQ || op == NE || op == LT || op == GE)
1458 && y == const0_rtx
1459 && GET_MODE (x) == SImode)
1460 {
1461 switch (GET_CODE (x))
1462 {
1463 case PLUS:
1464 case MINUS:
1465 case NEG:
1466 case AND:
1467 case IOR:
1468 case XOR:
1469 case NOT:
1470 case ASHIFT:
1471 case LSHIFTRT:
1472 case ASHIFTRT:
1473 return CC_NZmode;
1474
1475 case SIGN_EXTEND:
1476 case ZERO_EXTEND:
1477 case ROTATE:
1478 case ROTATERT:
1479 return (op == LT || op == GE) ? CC_Nmode : CCmode;
1480
1481 default:
1482 return CCmode;
1483 }
1484 }
1485
1486 if ((op == EQ || op == NE)
1487 && (GET_CODE (y) == NEG)
1488 && register_operand (XEXP (y, 0), SImode)
1489 && register_operand (x, SImode))
1490 {
1491 return CC_NZmode;
1492 }
1493
1494 return CCmode;
1495 }
1496
1497 /* Generate the prologue instructions for entry into a S+core function. */
1498 void
1499 score_prologue (void)
1500 {
1501 #define EMIT_PL(_rtx) RTX_FRAME_RELATED_P (_rtx) = 1
1502
1503 struct score_frame_info *f = score_compute_frame_size (get_frame_size ());
1504 HOST_WIDE_INT size;
1505 int regno;
1506
1507 size = f->total_size - f->gp_reg_size;
1508
1509 if (flag_pic)
1510 emit_insn (gen_cpload_score7 ());
1511
1512 for (regno = (int) GP_REG_LAST; regno >= (int) GP_REG_FIRST; regno--)
1513 {
1514 if (BITSET_P (f->mask, regno - GP_REG_FIRST))
1515 {
1516 rtx mem = gen_rtx_MEM (SImode,
1517 gen_rtx_PRE_DEC (SImode, stack_pointer_rtx));
1518 rtx reg = gen_rtx_REG (SImode, regno);
1519 if (!crtl->calls_eh_return)
1520 MEM_READONLY_P (mem) = 1;
1521 EMIT_PL (emit_insn (gen_pushsi_score7 (mem, reg)));
1522 }
1523 }
1524
1525 if (size > 0)
1526 {
1527 rtx insn;
1528
1529 if (size >= -32768 && size <= 32767)
1530 EMIT_PL (emit_insn (gen_add3_insn (stack_pointer_rtx,
1531 stack_pointer_rtx,
1532 GEN_INT (-size))));
1533 else
1534 {
1535 EMIT_PL (emit_move_insn (gen_rtx_REG (Pmode, SCORE_PROLOGUE_TEMP_REGNUM),
1536 GEN_INT (size)));
1537 EMIT_PL (emit_insn
1538 (gen_sub3_insn (stack_pointer_rtx,
1539 stack_pointer_rtx,
1540 gen_rtx_REG (Pmode,
1541 SCORE_PROLOGUE_TEMP_REGNUM))));
1542 }
1543 insn = get_last_insn ();
1544 REG_NOTES (insn) =
1545 alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR,
1546 gen_rtx_SET (VOIDmode, stack_pointer_rtx,
1547 plus_constant (Pmode, stack_pointer_rtx,
1548 -size)),
1549 REG_NOTES (insn));
1550 }
1551
1552 if (frame_pointer_needed)
1553 EMIT_PL (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
1554
1555 if (flag_pic && f->cprestore_size)
1556 {
1557 if (frame_pointer_needed)
1558 emit_insn (gen_cprestore_use_fp_score7 (GEN_INT (size - f->cprestore_size)));
1559 else
1560 emit_insn (gen_cprestore_use_sp_score7 (GEN_INT (size - f->cprestore_size)));
1561 }
1562
1563 #undef EMIT_PL
1564 }
1565
1566 /* Generate the epilogue instructions in a S+core function. */
1567 void
1568 score_epilogue (int sibcall_p)
1569 {
1570 struct score_frame_info *f = score_compute_frame_size (get_frame_size ());
1571 HOST_WIDE_INT size;
1572 int regno;
1573 rtx base;
1574
1575 size = f->total_size - f->gp_reg_size;
1576
1577 if (!frame_pointer_needed)
1578 base = stack_pointer_rtx;
1579 else
1580 base = hard_frame_pointer_rtx;
1581
1582 if (size)
1583 {
1584 if (size >= -32768 && size <= 32767)
1585 emit_insn (gen_add3_insn (base, base, GEN_INT (size)));
1586 else
1587 {
1588 emit_move_insn (gen_rtx_REG (Pmode, SCORE_EPILOGUE_TEMP_REGNUM),
1589 GEN_INT (size));
1590 emit_insn (gen_add3_insn (base, base,
1591 gen_rtx_REG (Pmode,
1592 SCORE_EPILOGUE_TEMP_REGNUM)));
1593 }
1594 }
1595
1596 if (base != stack_pointer_rtx)
1597 emit_move_insn (stack_pointer_rtx, base);
1598
1599 if (crtl->calls_eh_return)
1600 emit_insn (gen_add3_insn (stack_pointer_rtx,
1601 stack_pointer_rtx,
1602 EH_RETURN_STACKADJ_RTX));
1603
1604 for (regno = (int) GP_REG_FIRST; regno <= (int) GP_REG_LAST; regno++)
1605 {
1606 if (BITSET_P (f->mask, regno - GP_REG_FIRST))
1607 {
1608 rtx mem = gen_rtx_MEM (SImode,
1609 gen_rtx_POST_INC (SImode, stack_pointer_rtx));
1610 rtx reg = gen_rtx_REG (SImode, regno);
1611
1612 if (!crtl->calls_eh_return)
1613 MEM_READONLY_P (mem) = 1;
1614
1615 emit_insn (gen_popsi_score7 (reg, mem));
1616 }
1617 }
1618
1619 if (!sibcall_p)
1620 emit_jump_insn (gen_return_internal_score7 (gen_rtx_REG (Pmode, RA_REGNUM)));
1621 }
1622
1623 /* Return true if X is a symbolic constant that can be calculated in
1624 the same way as a bare symbol. If it is, store the type of the
1625 symbol in *SYMBOL_TYPE. */
1626 int
1627 score_symbolic_constant_p (rtx x, enum score_symbol_type *symbol_type)
1628 {
1629 HOST_WIDE_INT offset;
1630
1631 score_split_const (x, &x, &offset);
1632 if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
1633 *symbol_type = score_classify_symbol (x);
1634 else
1635 return 0;
1636
1637 if (offset == 0)
1638 return 1;
1639
1640 /* if offset > 15bit, must reload */
1641 if (!IMM_IN_RANGE (offset, 15, 1))
1642 return 0;
1643
1644 switch (*symbol_type)
1645 {
1646 case SYMBOL_GENERAL:
1647 return 1;
1648 case SYMBOL_SMALL_DATA:
1649 return score_offset_within_object_p (x, offset);
1650 }
1651 gcc_unreachable ();
1652 }
1653
1654 void
1655 score_movsicc (rtx *ops)
1656 {
1657 enum machine_mode mode;
1658
1659 mode = score_select_cc_mode (GET_CODE (ops[1]), ops[2], ops[3]);
1660 emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM),
1661 gen_rtx_COMPARE (mode, XEXP (ops[1], 0),
1662 XEXP (ops[1], 1))));
1663 }
1664
1665 /* Call and sibcall pattern all need call this function. */
1666 void
1667 score_call (rtx *ops, bool sib)
1668 {
1669 rtx addr = XEXP (ops[0], 0);
1670 if (!call_insn_operand (addr, VOIDmode))
1671 {
1672 rtx oaddr = addr;
1673 addr = gen_reg_rtx (Pmode);
1674 gen_move_insn (addr, oaddr);
1675 }
1676
1677 if (sib)
1678 emit_call_insn (gen_sibcall_internal_score7 (addr, ops[1]));
1679 else
1680 emit_call_insn (gen_call_internal_score7 (addr, ops[1]));
1681 }
1682
1683 /* Call value and sibcall value pattern all need call this function. */
1684 void
1685 score_call_value (rtx *ops, bool sib)
1686 {
1687 rtx result = ops[0];
1688 rtx addr = XEXP (ops[1], 0);
1689 rtx arg = ops[2];
1690
1691 if (!call_insn_operand (addr, VOIDmode))
1692 {
1693 rtx oaddr = addr;
1694 addr = gen_reg_rtx (Pmode);
1695 gen_move_insn (addr, oaddr);
1696 }
1697
1698 if (sib)
1699 emit_call_insn (gen_sibcall_value_internal_score7 (result, addr, arg));
1700 else
1701 emit_call_insn (gen_call_value_internal_score7 (result, addr, arg));
1702 }
1703
1704 /* Machine Split */
1705 void
1706 score_movdi (rtx *ops)
1707 {
1708 rtx dst = ops[0];
1709 rtx src = ops[1];
1710 rtx dst0 = score_subw (dst, 0);
1711 rtx dst1 = score_subw (dst, 1);
1712 rtx src0 = score_subw (src, 0);
1713 rtx src1 = score_subw (src, 1);
1714
1715 if (GET_CODE (dst0) == REG && reg_overlap_mentioned_p (dst0, src))
1716 {
1717 emit_move_insn (dst1, src1);
1718 emit_move_insn (dst0, src0);
1719 }
1720 else
1721 {
1722 emit_move_insn (dst0, src0);
1723 emit_move_insn (dst1, src1);
1724 }
1725 }
1726
1727 void
1728 score_zero_extract_andi (rtx *ops)
1729 {
1730 if (INTVAL (ops[1]) == 1 && const_uimm5 (ops[2], SImode))
1731 emit_insn (gen_zero_extract_bittst_score7 (ops[0], ops[2]));
1732 else
1733 {
1734 unsigned HOST_WIDE_INT mask;
1735 mask = (0xffffffffU & ((1U << INTVAL (ops[1])) - 1U));
1736 mask = mask << INTVAL (ops[2]);
1737 emit_insn (gen_andsi3_cmp_score7 (ops[3], ops[0],
1738 gen_int_mode (mask, SImode)));
1739 }
1740 }
1741
1742 /* Check addr could be present as PRE/POST mode. */
1743 static bool
1744 score_pindex_mem (rtx addr)
1745 {
1746 if (GET_CODE (addr) == MEM)
1747 {
1748 switch (GET_CODE (XEXP (addr, 0)))
1749 {
1750 case PRE_DEC:
1751 case POST_DEC:
1752 case PRE_INC:
1753 case POST_INC:
1754 return true;
1755 default:
1756 break;
1757 }
1758 }
1759 return false;
1760 }
1761
1762 /* Output asm code for ld/sw insn. */
1763 static int
1764 score_pr_addr_post (rtx *ops, int idata, int iaddr, char *ip, enum score_mem_unit unit)
1765 {
1766 struct score_address_info ai;
1767
1768 gcc_assert (GET_CODE (ops[idata]) == REG);
1769 gcc_assert (score_classify_address (&ai, SImode, XEXP (ops[iaddr], 0), true));
1770
1771 if (!score_pindex_mem (ops[iaddr])
1772 && ai.type == SCORE_ADD_REG
1773 && GET_CODE (ai.offset) == CONST_INT
1774 && G16_REG_P (REGNO (ops[idata]))
1775 && G16_REG_P (REGNO (ai.reg)))
1776 {
1777 if (INTVAL (ai.offset) == 0)
1778 {
1779 ops[iaddr] = ai.reg;
1780 return snprintf (ip, INS_BUF_SZ,
1781 "!\t%%%d, [%%%d]", idata, iaddr);
1782 }
1783 if (REGNO (ai.reg) == HARD_FRAME_POINTER_REGNUM)
1784 {
1785 HOST_WIDE_INT offset = INTVAL (ai.offset);
1786 if (SCORE_ALIGN_UNIT (offset, unit)
1787 && (((offset >> unit) >= 0) && ((offset >> unit) <= 31)))
1788 {
1789 ops[iaddr] = ai.offset;
1790 return snprintf (ip, INS_BUF_SZ,
1791 "p!\t%%%d, %%c%d", idata, iaddr);
1792 }
1793 }
1794 }
1795 return snprintf (ip, INS_BUF_SZ, "\t%%%d, %%a%d", idata, iaddr);
1796 }
1797
1798 /* Output asm insn for load. */
1799 const char *
1800 score_linsn (rtx *ops, enum score_mem_unit unit, bool sign)
1801 {
1802 const char *pre_ins[] =
1803 {"lbu", "lhu", "lw", "??", "lb", "lh", "lw", "??"};
1804 char *ip;
1805
1806 strcpy (score_ins, pre_ins[(sign ? 4 : 0) + unit]);
1807 ip = score_ins + strlen (score_ins);
1808
1809 if ((!sign && unit != SCORE_HWORD)
1810 || (sign && unit != SCORE_BYTE))
1811 score_pr_addr_post (ops, 0, 1, ip, unit);
1812 else
1813 snprintf (ip, INS_BUF_SZ, "\t%%0, %%a1");
1814
1815 return score_ins;
1816 }
1817
1818 /* Output asm insn for store. */
1819 const char *
1820 score_sinsn (rtx *ops, enum score_mem_unit unit)
1821 {
1822 const char *pre_ins[] = {"sb", "sh", "sw"};
1823 char *ip;
1824
1825 strcpy (score_ins, pre_ins[unit]);
1826 ip = score_ins + strlen (score_ins);
1827 score_pr_addr_post (ops, 1, 0, ip, unit);
1828 return score_ins;
1829 }
1830
1831 /* Output asm insn for load immediate. */
1832 const char *
1833 score_limm (rtx *ops)
1834 {
1835 HOST_WIDE_INT v;
1836
1837 gcc_assert (GET_CODE (ops[0]) == REG);
1838 gcc_assert (GET_CODE (ops[1]) == CONST_INT);
1839
1840 v = INTVAL (ops[1]);
1841 if (G16_REG_P (REGNO (ops[0])) && IMM_IN_RANGE (v, 8, 0))
1842 return "ldiu!\t%0, %c1";
1843 else if (IMM_IN_RANGE (v, 16, 1))
1844 return "ldi\t%0, %c1";
1845 else if ((v & 0xffff) == 0)
1846 return "ldis\t%0, %U1";
1847 else
1848 return "li\t%0, %c1";
1849 }
1850
1851 /* Output asm insn for move. */
1852 const char *
1853 score_move (rtx *ops)
1854 {
1855 gcc_assert (GET_CODE (ops[0]) == REG);
1856 gcc_assert (GET_CODE (ops[1]) == REG);
1857
1858 if (G16_REG_P (REGNO (ops[0])))
1859 {
1860 if (G16_REG_P (REGNO (ops[1])))
1861 return "mv!\t%0, %1";
1862 else
1863 return "mlfh!\t%0, %1";
1864 }
1865 else if (G16_REG_P (REGNO (ops[1])))
1866 return "mhfl!\t%0, %1";
1867 else
1868 return "mv\t%0, %1";
1869 }
1870
1871 /* Generate add insn. */
1872 const char *
1873 score_select_add_imm (rtx *ops, bool set_cc)
1874 {
1875 HOST_WIDE_INT v = INTVAL (ops[2]);
1876
1877 gcc_assert (GET_CODE (ops[2]) == CONST_INT);
1878 gcc_assert (REGNO (ops[0]) == REGNO (ops[1]));
1879
1880 if (set_cc && G16_REG_P (REGNO (ops[0])))
1881 {
1882 if (v > 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) v, 0, 15))
1883 {
1884 ops[2] = GEN_INT (ffs (v) - 1);
1885 return "addei!\t%0, %c2";
1886 }
1887
1888 if (v < 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) (-v), 0, 15))
1889 {
1890 ops[2] = GEN_INT (ffs (-v) - 1);
1891 return "subei!\t%0, %c2";
1892 }
1893 }
1894
1895 if (set_cc)
1896 return "addi.c\t%0, %c2";
1897 else
1898 return "addi\t%0, %c2";
1899 }
1900
1901 /* Output arith insn. */
1902 const char *
1903 score_select (rtx *ops, const char *inst_pre,
1904 bool commu, const char *letter, bool set_cc)
1905 {
1906 gcc_assert (GET_CODE (ops[0]) == REG);
1907 gcc_assert (GET_CODE (ops[1]) == REG);
1908
1909 if (set_cc && G16_REG_P (REGNO (ops[0]))
1910 && (GET_CODE (ops[2]) == REG ? G16_REG_P (REGNO (ops[2])) : 1)
1911 && REGNO (ops[0]) == REGNO (ops[1]))
1912 {
1913 snprintf (score_ins, INS_BUF_SZ, "%s!\t%%0, %%%s2", inst_pre, letter);
1914 return score_ins;
1915 }
1916
1917 if (commu && set_cc && G16_REG_P (REGNO (ops[0]))
1918 && G16_REG_P (REGNO (ops[1]))
1919 && REGNO (ops[0]) == REGNO (ops[2]))
1920 {
1921 gcc_assert (GET_CODE (ops[2]) == REG);
1922 snprintf (score_ins, INS_BUF_SZ, "%s!\t%%0, %%%s1", inst_pre, letter);
1923 return score_ins;
1924 }
1925
1926 if (set_cc)
1927 snprintf (score_ins, INS_BUF_SZ, "%s.c\t%%0, %%1, %%%s2", inst_pre, letter);
1928 else
1929 snprintf (score_ins, INS_BUF_SZ, "%s\t%%0, %%1, %%%s2", inst_pre, letter);
1930 return score_ins;
1931 }
1932
1933 /* Return nonzero when an argument must be passed by reference. */
1934 static bool
1935 score_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED,
1936 enum machine_mode mode, const_tree type,
1937 bool named ATTRIBUTE_UNUSED)
1938 {
1939 /* If we have a variable-sized parameter, we have no choice. */
1940 return targetm.calls.must_pass_in_stack (mode, type);
1941 }
1942
1943 /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */
1944 static bool
1945 score_function_ok_for_sibcall (ATTRIBUTE_UNUSED tree decl,
1946 ATTRIBUTE_UNUSED tree exp)
1947 {
1948 return true;
1949 }
1950
1951 /* Implement TARGET_SCHED_ISSUE_RATE. */
1952 static int
1953 score_issue_rate (void)
1954 {
1955 return 1;
1956 }
1957
1958 /* We can always eliminate to the hard frame pointer. We can eliminate
1959 to the stack pointer unless a frame pointer is needed. */
1960
1961 static bool
1962 score_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)
1963 {
1964 return (to == HARD_FRAME_POINTER_REGNUM
1965 || (to == STACK_POINTER_REGNUM && !frame_pointer_needed));
1966 }
1967
1968 /* Argument support functions. */
1969
1970 /* Initialize CUMULATIVE_ARGS for a function. */
1971 void
1972 score_init_cumulative_args (CUMULATIVE_ARGS *cum,
1973 tree fntype ATTRIBUTE_UNUSED,
1974 rtx libname ATTRIBUTE_UNUSED)
1975 {
1976 memset (cum, 0, sizeof (CUMULATIVE_ARGS));
1977 }
1978
1979 static void
1980 score_conditional_register_usage (void)
1981 {
1982 if (!flag_pic)
1983 fixed_regs[PIC_OFFSET_TABLE_REGNUM] =
1984 call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 0;
1985 }
1986
1987 struct gcc_target targetm = TARGET_INITIALIZER;