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