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