comparison gcc/config/score/score7.c @ 0:a06113de4d67

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