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