renam ms1 files to mt (part 2)
[gcc.git] / gcc / config / mt / mt.c
1 /* Target definitions for the MorphoRISC1
2 Copyright (C) 2005 Free Software Foundation, Inc.
3 Contributed by Red Hat, Inc.
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 2, 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 COPYING. If not, write to the Free
19 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301, USA. */
21
22 #include "config.h"
23 #include "system.h"
24 #include "coretypes.h"
25 #include "tm.h"
26 #include "rtl.h"
27 #include "regs.h"
28 #include "hard-reg-set.h"
29 #include "real.h"
30 #include "insn-config.h"
31 #include "conditions.h"
32 #include "insn-attr.h"
33 #include "recog.h"
34 #include "toplev.h"
35 #include "output.h"
36 #include "integrate.h"
37 #include "tree.h"
38 #include "function.h"
39 #include "expr.h"
40 #include "optabs.h"
41 #include "libfuncs.h"
42 #include "flags.h"
43 #include "tm_p.h"
44 #include "ggc.h"
45 #include "insn-flags.h"
46 #include "obstack.h"
47 #include "except.h"
48 #include "target.h"
49 #include "target-def.h"
50 #include "basic-block.h"
51
52 /* Frame pointer register mask. */
53 #define FP_MASK (1 << (GPR_FP))
54
55 /* Link register mask. */
56 #define LINK_MASK (1 << (GPR_LINK))
57
58 /* First GPR. */
59 #define MS1_INT_ARG_FIRST 1
60
61 /* Given a SIZE in bytes, advance to the next word. */
62 #define ROUND_ADVANCE(SIZE) (((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
63
64 /* A C structure for machine-specific, per-function data.
65 This is added to the cfun structure. */
66 struct machine_function GTY(())
67 {
68 /* Flags if __builtin_return_address (n) with n >= 1 was used. */
69 int ra_needs_full_frame;
70 struct rtx_def * eh_stack_adjust;
71 int interrupt_handler;
72 int has_loops;
73 };
74
75 /* Define the information needed to generate branch and scc insns.
76 This is stored from the compare operation. */
77 struct rtx_def * ms1_compare_op0;
78 struct rtx_def * ms1_compare_op1;
79
80 /* Current frame information calculated by compute_frame_size. */
81 struct ms1_frame_info current_frame_info;
82
83 /* Zero structure to initialize current_frame_info. */
84 struct ms1_frame_info zero_frame_info;
85
86 /* ms1 doesn't have unsigned compares need a library call for this. */
87 struct rtx_def * ms1_ucmpsi3_libcall;
88
89 static int ms1_flag_delayed_branch;
90
91 \f
92 static rtx
93 ms1_struct_value_rtx (tree fndecl ATTRIBUTE_UNUSED,
94 int incoming ATTRIBUTE_UNUSED)
95 {
96 return gen_rtx_REG (Pmode, RETVAL_REGNUM);
97 }
98
99 /* Implement RETURN_ADDR_RTX. */
100 rtx
101 ms1_return_addr_rtx (int count)
102 {
103 if (count != 0)
104 return NULL_RTX;
105
106 return get_hard_reg_initial_val (Pmode, GPR_LINK);
107 }
108
109 /* The following variable value indicates the number of nops required
110 between the current instruction and the next instruction to avoid
111 any pipeline hazards. */
112 static int ms1_nops_required = 0;
113 static const char * ms1_nop_reasons = "";
114
115 /* Implement ASM_OUTPUT_OPCODE. */
116 const char *
117 ms1_asm_output_opcode (FILE *f ATTRIBUTE_UNUSED, const char *ptr)
118 {
119 if (ms1_nops_required)
120 fprintf (f, ";# need %d nops because of %s\n\t",
121 ms1_nops_required, ms1_nop_reasons);
122
123 while (ms1_nops_required)
124 {
125 fprintf (f, "or r0, r0, r0\n\t");
126 -- ms1_nops_required;
127 }
128
129 return ptr;
130 }
131
132 /* Given an insn, return whether it's a memory operation or a branch
133 operation, otherwise return TYPE_ARITH. */
134 static enum attr_type
135 ms1_get_attr_type (rtx complete_insn)
136 {
137 rtx insn = PATTERN (complete_insn);
138
139 if (JUMP_P (complete_insn))
140 return TYPE_BRANCH;
141 if (CALL_P (complete_insn))
142 return TYPE_BRANCH;
143
144 if (GET_CODE (insn) != SET)
145 return TYPE_ARITH;
146
147 if (SET_DEST (insn) == pc_rtx)
148 return TYPE_BRANCH;
149
150 if (GET_CODE (SET_DEST (insn)) == MEM)
151 return TYPE_STORE;
152
153 if (GET_CODE (SET_SRC (insn)) == MEM)
154 return TYPE_LOAD;
155
156 return TYPE_ARITH;
157 }
158
159 /* A helper routine for insn_dependent_p called through note_stores. */
160
161 static void
162 insn_dependent_p_1 (rtx x, rtx pat ATTRIBUTE_UNUSED, void *data)
163 {
164 rtx * pinsn = (rtx *) data;
165
166 if (*pinsn && reg_mentioned_p (x, *pinsn))
167 *pinsn = NULL_RTX;
168 }
169
170 /* Return true if anything in insn X is (anti,output,true)
171 dependent on anything in insn Y. */
172
173 static bool
174 insn_dependent_p (rtx x, rtx y)
175 {
176 rtx tmp;
177
178 if (! INSN_P (x) || ! INSN_P (y))
179 return 0;
180
181 tmp = PATTERN (y);
182 note_stores (PATTERN (x), insn_dependent_p_1, &tmp);
183 if (tmp == NULL_RTX)
184 return true;
185
186 tmp = PATTERN (x);
187 note_stores (PATTERN (y), insn_dependent_p_1, &tmp);
188 return (tmp == NULL_RTX);
189 }
190
191
192 /* Return true if anything in insn X is true dependent on anything in
193 insn Y. */
194 static bool
195 insn_true_dependent_p (rtx x, rtx y)
196 {
197 rtx tmp;
198
199 if (! INSN_P (x) || ! INSN_P (y))
200 return 0;
201
202 tmp = PATTERN (y);
203 note_stores (PATTERN (x), insn_dependent_p_1, &tmp);
204 return (tmp == NULL_RTX);
205 }
206
207 /* The following determines the number of nops that need to be
208 inserted between the previous instructions and current instruction
209 to avoid pipeline hazards on the ms1 processor. Remember that
210 the function is not called for asm insns. */
211
212 void
213 ms1_final_prescan_insn (rtx insn,
214 rtx * opvec ATTRIBUTE_UNUSED,
215 int noperands ATTRIBUTE_UNUSED)
216 {
217 rtx prev_i;
218 enum attr_type prev_attr;
219
220 ms1_nops_required = 0;
221 ms1_nop_reasons = "";
222
223 /* ms2 constraints are dealt with in reorg. */
224 if (ms1_cpu == PROCESSOR_MS2)
225 return;
226
227 /* Only worry about real instructions. */
228 if (! INSN_P (insn))
229 return;
230
231 /* Find the previous real instructions. */
232 for (prev_i = PREV_INSN (insn);
233 prev_i != NULL
234 && (! INSN_P (prev_i)
235 || GET_CODE (PATTERN (prev_i)) == USE
236 || GET_CODE (PATTERN (prev_i)) == CLOBBER);
237 prev_i = PREV_INSN (prev_i))
238 {
239 /* If we meet a barrier, there is no flow through here. */
240 if (BARRIER_P (prev_i))
241 return;
242 }
243
244 /* If there isn't one then there is nothing that we need do. */
245 if (prev_i == NULL || ! INSN_P (prev_i))
246 return;
247
248 prev_attr = ms1_get_attr_type (prev_i);
249
250 /* Delayed branch slots already taken care of by delay branch scheduling. */
251 if (prev_attr == TYPE_BRANCH)
252 return;
253
254 switch (ms1_get_attr_type (insn))
255 {
256 case TYPE_LOAD:
257 case TYPE_STORE:
258 /* Avoid consecutive memory operation. */
259 if ((prev_attr == TYPE_LOAD || prev_attr == TYPE_STORE)
260 && ms1_cpu == PROCESSOR_MS1_64_001)
261 {
262 ms1_nops_required = 1;
263 ms1_nop_reasons = "consecutive mem ops";
264 }
265 /* Drop through. */
266
267 case TYPE_ARITH:
268 case TYPE_COMPLEX:
269 /* One cycle of delay is required between load
270 and the dependent arithmetic instruction. */
271 if (prev_attr == TYPE_LOAD
272 && insn_true_dependent_p (prev_i, insn))
273 {
274 ms1_nops_required = 1;
275 ms1_nop_reasons = "load->arith dependency delay";
276 }
277 break;
278
279 case TYPE_BRANCH:
280 if (insn_dependent_p (prev_i, insn))
281 {
282 if (prev_attr == TYPE_ARITH
283 && ms1_cpu == PROCESSOR_MS1_64_001)
284 {
285 /* One cycle of delay between arith
286 instructions and branch dependent on arith. */
287 ms1_nops_required = 1;
288 ms1_nop_reasons = "arith->branch dependency delay";
289 }
290 else if (prev_attr == TYPE_LOAD)
291 {
292 /* Two cycles of delay are required
293 between load and dependent branch. */
294 if (ms1_cpu == PROCESSOR_MS1_64_001)
295 ms1_nops_required = 2;
296 else
297 ms1_nops_required = 1;
298 ms1_nop_reasons = "load->branch dependency delay";
299 }
300 }
301 break;
302
303 default:
304 fatal_insn ("ms1_final_prescan_insn, invalid insn #1", insn);
305 break;
306 }
307 }
308
309 /* Print debugging information for a frame. */
310 static void
311 ms1_debug_stack (struct ms1_frame_info * info)
312 {
313 int regno;
314
315 if (!info)
316 {
317 error ("info pointer NULL");
318 gcc_unreachable ();
319 }
320
321 fprintf (stderr, "\nStack information for function %s:\n",
322 ((current_function_decl && DECL_NAME (current_function_decl))
323 ? IDENTIFIER_POINTER (DECL_NAME (current_function_decl))
324 : "<unknown>"));
325
326 fprintf (stderr, "\ttotal_size = %d\n", info->total_size);
327 fprintf (stderr, "\tpretend_size = %d\n", info->pretend_size);
328 fprintf (stderr, "\targs_size = %d\n", info->args_size);
329 fprintf (stderr, "\textra_size = %d\n", info->extra_size);
330 fprintf (stderr, "\treg_size = %d\n", info->reg_size);
331 fprintf (stderr, "\tvar_size = %d\n", info->var_size);
332 fprintf (stderr, "\tframe_size = %d\n", info->frame_size);
333 fprintf (stderr, "\treg_mask = 0x%x\n", info->reg_mask);
334 fprintf (stderr, "\tsave_fp = %d\n", info->save_fp);
335 fprintf (stderr, "\tsave_lr = %d\n", info->save_lr);
336 fprintf (stderr, "\tinitialized = %d\n", info->initialized);
337 fprintf (stderr, "\tsaved registers =");
338
339 /* Print out reg_mask in a more readable format. */
340 for (regno = GPR_R0; regno <= GPR_LAST; regno++)
341 if ( (1 << regno) & info->reg_mask)
342 fprintf (stderr, " %s", reg_names[regno]);
343
344 putc ('\n', stderr);
345 fflush (stderr);
346 }
347
348 /* Print a memory address as an operand to reference that memory location. */
349
350 static void
351 ms1_print_operand_simple_address (FILE * file, rtx addr)
352 {
353 if (!addr)
354 error ("PRINT_OPERAND_ADDRESS, null pointer");
355
356 else
357 switch (GET_CODE (addr))
358 {
359 case REG:
360 fprintf (file, "%s, #0", reg_names [REGNO (addr)]);
361 break;
362
363 case PLUS:
364 {
365 rtx reg = 0;
366 rtx offset = 0;
367 rtx arg0 = XEXP (addr, 0);
368 rtx arg1 = XEXP (addr, 1);
369
370 if (GET_CODE (arg0) == REG)
371 {
372 reg = arg0;
373 offset = arg1;
374 if (GET_CODE (offset) == REG)
375 fatal_insn ("PRINT_OPERAND_ADDRESS, 2 regs", addr);
376 }
377
378 else if (GET_CODE (arg1) == REG)
379 reg = arg1, offset = arg0;
380 else if (CONSTANT_P (arg0) && CONSTANT_P (arg1))
381 {
382 fprintf (file, "%s, #", reg_names [GPR_R0]);
383 output_addr_const (file, addr);
384 break;
385 }
386 fprintf (file, "%s, #", reg_names [REGNO (reg)]);
387 output_addr_const (file, offset);
388 break;
389 }
390
391 case LABEL_REF:
392 case SYMBOL_REF:
393 case CONST_INT:
394 case CONST:
395 output_addr_const (file, addr);
396 break;
397
398 default:
399 fatal_insn ("PRINT_OPERAND_ADDRESS, invalid insn #1", addr);
400 break;
401 }
402 }
403
404 /* Implement PRINT_OPERAND_ADDRESS. */
405 void
406 ms1_print_operand_address (FILE * file, rtx addr)
407 {
408 if (GET_CODE (addr) == AND
409 && GET_CODE (XEXP (addr, 1)) == CONST_INT
410 && INTVAL (XEXP (addr, 1)) == -3)
411 ms1_print_operand_simple_address (file, XEXP (addr, 0));
412 else
413 ms1_print_operand_simple_address (file, addr);
414 }
415
416 /* Implement PRINT_OPERAND. */
417 void
418 ms1_print_operand (FILE * file, rtx x, int code)
419 {
420 switch (code)
421 {
422 case '#':
423 /* Output a nop if there's nothing for the delay slot. */
424 if (dbr_sequence_length () == 0)
425 fputs ("\n\tor r0, r0, r0", file);
426 return;
427
428 case 'H':
429 fprintf(file, "#%%hi16(");
430 output_addr_const (file, x);
431 fprintf(file, ")");
432 return;
433
434 case 'L':
435 fprintf(file, "#%%lo16(");
436 output_addr_const (file, x);
437 fprintf(file, ")");
438 return;
439
440 case 'N':
441 fprintf(file, "#%ld", ~INTVAL (x));
442 return;
443
444 case 'z':
445 if (GET_CODE (x) == CONST_INT && INTVAL (x) == 0)
446 {
447 fputs (reg_names[GPR_R0], file);
448 return;
449 }
450
451 case 0:
452 /* Handled below. */
453 break;
454
455 default:
456 /* output_operand_lossage ("ms1_print_operand: unknown code"); */
457 fprintf (file, "unknown code");
458 return;
459 }
460
461 switch (GET_CODE (x))
462 {
463 case REG:
464 fputs (reg_names [REGNO (x)], file);
465 break;
466
467 case CONST:
468 case CONST_INT:
469 fprintf(file, "#%ld", INTVAL (x));
470 break;
471
472 case MEM:
473 ms1_print_operand_address(file, XEXP (x,0));
474 break;
475
476 case LABEL_REF:
477 case SYMBOL_REF:
478 output_addr_const (file, x);
479 break;
480
481 default:
482 fprintf(file, "Uknown code: %d", GET_CODE (x));
483 break;
484 }
485
486 return;
487 }
488
489 /* Implement INIT_CUMULATIVE_ARGS. */
490 void
491 ms1_init_cumulative_args (CUMULATIVE_ARGS * cum, tree fntype, rtx libname,
492 tree fndecl ATTRIBUTE_UNUSED, int incoming)
493 {
494 *cum = 0;
495
496 if (TARGET_DEBUG_ARG)
497 {
498 fprintf (stderr, "\nms1_init_cumulative_args:");
499
500 if (incoming)
501 fputs (" incoming", stderr);
502
503 if (fntype)
504 {
505 tree ret_type = TREE_TYPE (fntype);
506 fprintf (stderr, " return = %s,",
507 tree_code_name[ (int)TREE_CODE (ret_type) ]);
508 }
509
510 if (libname && GET_CODE (libname) == SYMBOL_REF)
511 fprintf (stderr, " libname = %s", XSTR (libname, 0));
512
513 if (cfun->returns_struct)
514 fprintf (stderr, " return-struct");
515
516 putc ('\n', stderr);
517 }
518 }
519
520 /* Compute the slot number to pass an argument in.
521 Returns the slot number or -1 if passing on the stack.
522
523 CUM is a variable of type CUMULATIVE_ARGS which gives info about
524 the preceding args and about the function being called.
525 MODE is the argument's machine mode.
526 TYPE is the data type of the argument (as a tree).
527 This is null for libcalls where that information may
528 not be available.
529 NAMED is nonzero if this argument is a named parameter
530 (otherwise it is an extra parameter matching an ellipsis).
531 INCOMING_P is zero for FUNCTION_ARG, nonzero for FUNCTION_INCOMING_ARG.
532 *PREGNO records the register number to use if scalar type. */
533
534 static int
535 ms1_function_arg_slotno (const CUMULATIVE_ARGS * cum,
536 enum machine_mode mode,
537 tree type,
538 int named ATTRIBUTE_UNUSED,
539 int incoming_p ATTRIBUTE_UNUSED,
540 int * pregno)
541 {
542 int regbase = MS1_INT_ARG_FIRST;
543 int slotno = * cum;
544
545 if (mode == VOIDmode || targetm.calls.must_pass_in_stack (mode, type))
546 return -1;
547
548 if (slotno >= MS1_NUM_ARG_REGS)
549 return -1;
550
551 * pregno = regbase + slotno;
552
553 return slotno;
554 }
555
556 /* Implement FUNCTION_ARG. */
557 rtx
558 ms1_function_arg (const CUMULATIVE_ARGS * cum,
559 enum machine_mode mode,
560 tree type,
561 int named,
562 int incoming_p)
563 {
564 int slotno, regno;
565 rtx reg;
566
567 slotno = ms1_function_arg_slotno (cum, mode, type, named, incoming_p,
568 & regno);
569
570 if (slotno == -1)
571 reg = NULL_RTX;
572 else
573 reg = gen_rtx_REG (mode, regno);
574
575 return reg;
576 }
577
578 /* Implement FUNCTION_ARG_ADVANCE. */
579 void
580 ms1_function_arg_advance (CUMULATIVE_ARGS * cum,
581 enum machine_mode mode,
582 tree type ATTRIBUTE_UNUSED,
583 int named)
584 {
585 int slotno, regno;
586
587 /* We pass 0 for incoming_p here, it doesn't matter. */
588 slotno = ms1_function_arg_slotno (cum, mode, type, named, 0, &regno);
589
590 * cum += (mode != BLKmode
591 ? ROUND_ADVANCE (GET_MODE_SIZE (mode))
592 : ROUND_ADVANCE (int_size_in_bytes (type)));
593
594 if (TARGET_DEBUG_ARG)
595 fprintf (stderr,
596 "ms1_function_arg_advance: words = %2d, mode = %4s, named = %d, size = %3d\n",
597 *cum, GET_MODE_NAME (mode), named,
598 (*cum) * UNITS_PER_WORD);
599 }
600
601 /* Implement hook TARGET_ARG_PARTIAL_BYTES.
602
603 Returns the number of bytes at the beginning of an argument that
604 must be put in registers. The value must be zero for arguments
605 that are passed entirely in registers or that are entirely pushed
606 on the stack. */
607 static int
608 ms1_arg_partial_bytes (CUMULATIVE_ARGS * pcum,
609 enum machine_mode mode,
610 tree type,
611 bool named ATTRIBUTE_UNUSED)
612 {
613 int cum = * pcum;
614 int words;
615
616 if (mode == BLKmode)
617 words = ((int_size_in_bytes (type) + UNITS_PER_WORD - 1)
618 / UNITS_PER_WORD);
619 else
620 words = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
621
622 if (! targetm.calls.pass_by_reference (& cum, mode, type, named)
623 && cum < MS1_NUM_ARG_REGS
624 && (cum + words) > MS1_NUM_ARG_REGS)
625 {
626 int bytes = (MS1_NUM_ARG_REGS - cum) * UNITS_PER_WORD;
627
628 if (TARGET_DEBUG)
629 fprintf (stderr, "function_arg_partial_nregs = %d\n", bytes);
630 return bytes;
631 }
632
633 return 0;
634 }
635
636
637 /* Implement TARGET_PASS_BY_REFERENCE hook. */
638 static bool
639 ms1_pass_by_reference (CUMULATIVE_ARGS * cum ATTRIBUTE_UNUSED,
640 enum machine_mode mode ATTRIBUTE_UNUSED,
641 tree type,
642 bool named ATTRIBUTE_UNUSED)
643 {
644 return (type && int_size_in_bytes (type) > 4 * UNITS_PER_WORD);
645 }
646
647 /* Implement FUNCTION_ARG_BOUNDARY. */
648 int
649 ms1_function_arg_boundary (enum machine_mode mode ATTRIBUTE_UNUSED,
650 tree type ATTRIBUTE_UNUSED)
651 {
652 return BITS_PER_WORD;
653 }
654
655 /* Implement REG_OK_FOR_BASE_P. */
656 int
657 ms1_reg_ok_for_base_p (rtx x, int strict)
658 {
659 if (strict)
660 return (((unsigned) REGNO (x)) < FIRST_PSEUDO_REGISTER);
661 return 1;
662 }
663
664 /* Helper function of ms1_legitimate_address_p. Return true if XINSN
665 is a simple address, otherwise false. */
666 static bool
667 ms1_legitimate_simple_address_p (enum machine_mode mode ATTRIBUTE_UNUSED,
668 rtx xinsn,
669 int strict)
670 {
671 if (TARGET_DEBUG)
672 {
673 fprintf (stderr, "\n========== GO_IF_LEGITIMATE_ADDRESS, %sstrict\n",
674 strict ? "" : "not ");
675 debug_rtx (xinsn);
676 }
677
678 if (GET_CODE (xinsn) == REG && ms1_reg_ok_for_base_p (xinsn, strict))
679 return true;
680
681 if (GET_CODE (xinsn) == PLUS
682 && GET_CODE (XEXP (xinsn, 0)) == REG
683 && ms1_reg_ok_for_base_p (XEXP (xinsn, 0), strict)
684 && GET_CODE (XEXP (xinsn, 1)) == CONST_INT
685 && SMALL_INT (XEXP (xinsn, 1)))
686 return true;
687
688 return false;
689 }
690
691
692 /* Helper function of GO_IF_LEGITIMATE_ADDRESS. Return non-zero if
693 XINSN is a legitimate address on MS1. */
694 int
695 ms1_legitimate_address_p (enum machine_mode mode,
696 rtx xinsn,
697 int strict)
698 {
699 if (ms1_legitimate_simple_address_p (mode, xinsn, strict))
700 return 1;
701
702 if ((mode) == SImode
703 && GET_CODE (xinsn) == AND
704 && GET_CODE (XEXP (xinsn, 1)) == CONST_INT
705 && INTVAL (XEXP (xinsn, 1)) == -3)
706 return ms1_legitimate_simple_address_p (mode, XEXP (xinsn, 0), strict);
707 else
708 return 0;
709 }
710
711 /* Return truth value of whether OP can be used as an operands where a
712 register or 16 bit unsigned integer is needed. */
713
714 int
715 uns_arith_operand (rtx op, enum machine_mode mode)
716 {
717 if (GET_CODE (op) == CONST_INT && SMALL_INT_UNSIGNED (op))
718 return 1;
719
720 return register_operand (op, mode);
721 }
722
723 /* Return truth value of whether OP can be used as an operands where a
724 16 bit integer is needed. */
725
726 int
727 arith_operand (rtx op, enum machine_mode mode)
728 {
729 if (GET_CODE (op) == CONST_INT && SMALL_INT (op))
730 return 1;
731
732 return register_operand (op, mode);
733 }
734
735 /* Return truth value of whether OP is a register or the constant 0. */
736
737 int
738 reg_or_0_operand (rtx op, enum machine_mode mode)
739 {
740 switch (GET_CODE (op))
741 {
742 case CONST_INT:
743 return INTVAL (op) == 0;
744
745 case REG:
746 case SUBREG:
747 return register_operand (op, mode);
748
749 default:
750 break;
751 }
752
753 return 0;
754 }
755
756 /* Return truth value of whether OP is a constant that requires two
757 loads to put in a register. */
758
759 int
760 big_const_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
761 {
762 if (GET_CODE (op) == CONST_INT && CONST_OK_FOR_LETTER_P (INTVAL (op), 'M'))
763 return 1;
764
765 return 0;
766 }
767
768 /* Return truth value of whether OP is a constant that require only
769 one load to put in a register. */
770
771 int
772 single_const_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
773 {
774 if (big_const_operand (op, mode)
775 || GET_CODE (op) == CONST
776 || GET_CODE (op) == LABEL_REF
777 || GET_CODE (op) == SYMBOL_REF)
778 return 0;
779
780 return 1;
781 }
782
783 /* True if the current function is an interrupt handler
784 (either via #pragma or an attribute specification). */
785 int interrupt_handler;
786 enum processor_type ms1_cpu;
787
788 static struct machine_function *
789 ms1_init_machine_status (void)
790 {
791 struct machine_function *f;
792
793 f = ggc_alloc_cleared (sizeof (struct machine_function));
794
795 return f;
796 }
797
798 /* Implement OVERRIDE_OPTIONS. */
799 void
800 ms1_override_options (void)
801 {
802 if (ms1_cpu_string != NULL)
803 {
804 if (!strcasecmp (ms1_cpu_string, "MS1-64-001"))
805 ms1_cpu = PROCESSOR_MS1_64_001;
806 else if (!strcasecmp (ms1_cpu_string, "MS1-16-002"))
807 ms1_cpu = PROCESSOR_MS1_16_002;
808 else if (!strcasecmp (ms1_cpu_string, "MS1-16-003"))
809 ms1_cpu = PROCESSOR_MS1_16_003;
810 else if (!strcasecmp (ms1_cpu_string, "MS2"))
811 ms1_cpu = PROCESSOR_MS2;
812 else
813 error ("bad value (%s) for -march= switch", ms1_cpu_string);
814 }
815 else
816 ms1_cpu = PROCESSOR_MS2;
817
818 if (flag_exceptions)
819 {
820 flag_omit_frame_pointer = 0;
821 flag_gcse = 0;
822 }
823
824 /* We do delayed branch filling in machine dependent reorg */
825 ms1_flag_delayed_branch = flag_delayed_branch;
826 flag_delayed_branch = 0;
827
828 init_machine_status = ms1_init_machine_status;
829 }
830
831 /* Do what is necessary for `va_start'. We look at the current function
832 to determine if stdarg or varargs is used and return the address of the
833 first unnamed parameter. */
834
835 static rtx
836 ms1_builtin_saveregs (void)
837 {
838 int first_reg = 0;
839 rtx address;
840 int regno;
841
842 for (regno = first_reg; regno < MS1_NUM_ARG_REGS; regno ++)
843 emit_move_insn (gen_rtx_MEM (word_mode,
844 gen_rtx_PLUS (Pmode,
845 gen_rtx_REG (SImode, ARG_POINTER_REGNUM),
846 GEN_INT (UNITS_PER_WORD * regno))),
847 gen_rtx_REG (word_mode,
848 MS1_INT_ARG_FIRST + regno));
849
850 address = gen_rtx_PLUS (Pmode,
851 gen_rtx_REG (SImode, ARG_POINTER_REGNUM),
852 GEN_INT (UNITS_PER_WORD * first_reg));
853 return address;
854 }
855
856 /* Implement `va_start'. */
857
858 void
859 ms1_va_start (tree valist, rtx nextarg)
860 {
861 ms1_builtin_saveregs ();
862 std_expand_builtin_va_start (valist, nextarg);
863 }
864
865 /* Returns the number of bytes offset between the frame pointer and the stack
866 pointer for the current function. SIZE is the number of bytes of space
867 needed for local variables. */
868
869 unsigned int
870 ms1_compute_frame_size (int size)
871 {
872 int regno;
873 unsigned int total_size;
874 unsigned int var_size;
875 unsigned int args_size;
876 unsigned int pretend_size;
877 unsigned int extra_size;
878 unsigned int reg_size;
879 unsigned int frame_size;
880 unsigned int reg_mask;
881
882 var_size = size;
883 args_size = current_function_outgoing_args_size;
884 pretend_size = current_function_pretend_args_size;
885 extra_size = FIRST_PARM_OFFSET (0);
886 total_size = extra_size + pretend_size + args_size + var_size;
887 reg_size = 0;
888 reg_mask = 0;
889
890 /* Calculate space needed for registers. */
891 for (regno = GPR_R0; regno <= GPR_LAST; regno++)
892 {
893 if (MUST_SAVE_REGISTER (regno))
894 {
895 reg_size += UNITS_PER_WORD;
896 reg_mask |= 1 << regno;
897 }
898 }
899
900 current_frame_info.save_fp = (regs_ever_live [GPR_FP]
901 || frame_pointer_needed
902 || interrupt_handler);
903 current_frame_info.save_lr = (regs_ever_live [GPR_LINK]
904 || profile_flag
905 || interrupt_handler);
906
907 reg_size += (current_frame_info.save_fp + current_frame_info.save_lr)
908 * UNITS_PER_WORD;
909 total_size += reg_size;
910 total_size = ((total_size + 3) & ~3);
911
912 frame_size = total_size;
913
914 /* Save computed information. */
915 current_frame_info.pretend_size = pretend_size;
916 current_frame_info.var_size = var_size;
917 current_frame_info.args_size = args_size;
918 current_frame_info.reg_size = reg_size;
919 current_frame_info.frame_size = args_size + var_size;
920 current_frame_info.total_size = total_size;
921 current_frame_info.extra_size = extra_size;
922 current_frame_info.reg_mask = reg_mask;
923 current_frame_info.initialized = reload_completed;
924
925 return total_size;
926 }
927
928 /* Emit code to save REG in stack offset pointed to by MEM.
929 STACK_OFFSET is the offset from the SP where the save will happen.
930 This function sets the REG_FRAME_RELATED_EXPR note accordingly. */
931 static void
932 ms1_emit_save_restore (enum save_direction direction,
933 rtx reg,
934 rtx mem,
935 int stack_offset)
936 {
937 if (direction == FROM_PROCESSOR_TO_MEM)
938 {
939 rtx insn;
940
941 insn = emit_move_insn (mem, reg);
942 RTX_FRAME_RELATED_P (insn) = 1;
943 REG_NOTES (insn)
944 = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
945 gen_rtx_SET (VOIDmode,
946 gen_rtx_MEM
947 (SImode,
948 gen_rtx_PLUS (SImode,
949 stack_pointer_rtx,
950 GEN_INT (stack_offset))),
951 reg),
952 REG_NOTES (insn));
953 }
954 else
955 emit_move_insn (reg, mem);
956 }
957
958
959 /* Emit code to save the frame pointer in the prologue and restore
960 frame pointer in epilogue. */
961
962 static void
963 ms1_emit_save_fp (enum save_direction direction,
964 struct ms1_frame_info info)
965 {
966 rtx base_reg;
967 int reg_mask = info.reg_mask & ~(FP_MASK | LINK_MASK);
968 int offset = info.total_size;
969 int stack_offset = info.total_size;
970
971 /* If there is nothing to save, get out now. */
972 if (! info.save_fp && ! info.save_lr && ! reg_mask)
973 return;
974
975 /* If offset doesn't fit in a 15-bit signed integer,
976 uses a scratch registers to get a smaller offset. */
977 if (CONST_OK_FOR_LETTER_P(offset, 'O'))
978 base_reg = stack_pointer_rtx;
979 else
980 {
981 /* Use the scratch register R9 that holds old stack pointer. */
982 base_reg = gen_rtx_REG (SImode, GPR_R9);
983 offset = 0;
984 }
985
986 if (info.save_fp)
987 {
988 offset -= UNITS_PER_WORD;
989 stack_offset -= UNITS_PER_WORD;
990 ms1_emit_save_restore (direction, gen_rtx_REG (SImode, GPR_FP),
991 gen_rtx_MEM (SImode,
992 gen_rtx_PLUS (SImode, base_reg, GEN_INT (offset))),
993 stack_offset);
994 }
995 }
996
997 /* Emit code to save registers in the prologue and restore register
998 in epilogue. */
999
1000 static void
1001 ms1_emit_save_regs (enum save_direction direction,
1002 struct ms1_frame_info info)
1003 {
1004 rtx base_reg;
1005 int regno;
1006 int reg_mask = info.reg_mask & ~(FP_MASK | LINK_MASK);
1007 int offset = info.total_size;
1008 int stack_offset = info.total_size;
1009
1010 /* If there is nothing to save, get out now. */
1011 if (! info.save_fp && ! info.save_lr && ! reg_mask)
1012 return;
1013
1014 /* If offset doesn't fit in a 15-bit signed integer,
1015 uses a scratch registers to get a smaller offset. */
1016 if (CONST_OK_FOR_LETTER_P(offset, 'O'))
1017 base_reg = stack_pointer_rtx;
1018 else
1019 {
1020 /* Use the scratch register R9 that holds old stack pointer. */
1021 base_reg = gen_rtx_REG (SImode, GPR_R9);
1022 offset = 0;
1023 }
1024
1025 if (info.save_fp)
1026 {
1027 /* This just records the space for it, the actual move generated in
1028 ms1_emit_save_fp (). */
1029 offset -= UNITS_PER_WORD;
1030 stack_offset -= UNITS_PER_WORD;
1031 }
1032
1033 if (info.save_lr)
1034 {
1035 offset -= UNITS_PER_WORD;
1036 stack_offset -= UNITS_PER_WORD;
1037 ms1_emit_save_restore (direction, gen_rtx_REG (SImode, GPR_LINK),
1038 gen_rtx_MEM (SImode,
1039 gen_rtx_PLUS (SImode, base_reg, GEN_INT (offset))),
1040 stack_offset);
1041 }
1042
1043 /* Save any needed call-saved regs. */
1044 for (regno = GPR_R0; regno <= GPR_LAST; regno++)
1045 {
1046 if ((reg_mask & (1 << regno)) != 0)
1047 {
1048 offset -= UNITS_PER_WORD;
1049 stack_offset -= UNITS_PER_WORD;
1050 ms1_emit_save_restore (direction, gen_rtx_REG (SImode, regno),
1051 gen_rtx_MEM (SImode,
1052 gen_rtx_PLUS (SImode, base_reg, GEN_INT (offset))),
1053 stack_offset);
1054 }
1055 }
1056 }
1057
1058 /* Return true if FUNC is a function with the 'interrupt' attribute. */
1059 static bool
1060 ms1_interrupt_function_p (tree func)
1061 {
1062 tree a;
1063
1064 if (TREE_CODE (func) != FUNCTION_DECL)
1065 return false;
1066
1067 a = lookup_attribute ("interrupt", DECL_ATTRIBUTES (func));
1068 return a != NULL_TREE;
1069 }
1070
1071 /* Generate prologue code. */
1072 void
1073 ms1_expand_prologue (void)
1074 {
1075 rtx size_rtx, insn;
1076 unsigned int frame_size;
1077
1078 if (ms1_interrupt_function_p (current_function_decl))
1079 {
1080 interrupt_handler = 1;
1081 if (cfun->machine)
1082 cfun->machine->interrupt_handler = 1;
1083 }
1084
1085 ms1_compute_frame_size (get_frame_size ());
1086
1087 if (TARGET_DEBUG_STACK)
1088 ms1_debug_stack (&current_frame_info);
1089
1090 /* Compute size of stack adjustment. */
1091 frame_size = current_frame_info.total_size;
1092
1093 /* If offset doesn't fit in a 15-bit signed integer,
1094 uses a scratch registers to get a smaller offset. */
1095 if (CONST_OK_FOR_LETTER_P(frame_size, 'O'))
1096 size_rtx = GEN_INT (frame_size);
1097 else
1098 {
1099 /* We do not have any scratch registers. */
1100 gcc_assert (!interrupt_handler);
1101
1102 size_rtx = gen_rtx_REG (SImode, GPR_R9);
1103 insn = emit_move_insn (size_rtx, GEN_INT (frame_size & 0xffff0000));
1104 insn = emit_insn (gen_iorsi3 (size_rtx, size_rtx,
1105 GEN_INT (frame_size & 0x0000ffff)));
1106 }
1107
1108 /* Allocate stack for this frame. */
1109 /* Make stack adjustment and use scratch register if constant too
1110 large to fit as immediate. */
1111 if (frame_size)
1112 {
1113 insn = emit_insn (gen_subsi3 (stack_pointer_rtx,
1114 stack_pointer_rtx,
1115 size_rtx));
1116 RTX_FRAME_RELATED_P (insn) = 1;
1117 REG_NOTES (insn)
1118 = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
1119 gen_rtx_SET (VOIDmode,
1120 stack_pointer_rtx,
1121 gen_rtx_MINUS (SImode,
1122 stack_pointer_rtx,
1123 GEN_INT (frame_size))),
1124 REG_NOTES (insn));
1125 }
1126
1127 /* Set R9 to point to old sp if required for access to register save area. */
1128 if ( current_frame_info.reg_size != 0
1129 && !CONST_OK_FOR_LETTER_P (frame_size, 'O'))
1130 emit_insn (gen_addsi3 (size_rtx, size_rtx, stack_pointer_rtx));
1131
1132 /* Save the frame pointer. */
1133 ms1_emit_save_fp (FROM_PROCESSOR_TO_MEM, current_frame_info);
1134
1135 /* Now put the frame pointer into the frame pointer register. */
1136 if (frame_pointer_needed)
1137 {
1138 insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
1139 RTX_FRAME_RELATED_P (insn) = 1;
1140 }
1141
1142 /* Save the registers. */
1143 ms1_emit_save_regs (FROM_PROCESSOR_TO_MEM, current_frame_info);
1144
1145 /* If we are profiling, make sure no instructions are scheduled before
1146 the call to mcount. */
1147 if (profile_flag)
1148 emit_insn (gen_blockage ());
1149 }
1150
1151 /* Implement EPILOGUE_USES. */
1152 int
1153 ms1_epilogue_uses (int regno)
1154 {
1155 if (cfun->machine && cfun->machine->interrupt_handler && reload_completed)
1156 return 1;
1157 return regno == GPR_LINK;
1158 }
1159
1160 /* Generate epilogue. EH_MODE is NORMAL_EPILOGUE when generating a
1161 function epilogue, or EH_EPILOGUE when generating an EH
1162 epilogue. */
1163 void
1164 ms1_expand_epilogue (enum epilogue_type eh_mode)
1165 {
1166 rtx size_rtx, insn;
1167 unsigned frame_size;
1168
1169 ms1_compute_frame_size (get_frame_size ());
1170
1171 if (TARGET_DEBUG_STACK)
1172 ms1_debug_stack (& current_frame_info);
1173
1174 /* Compute size of stack adjustment. */
1175 frame_size = current_frame_info.total_size;
1176
1177 /* If offset doesn't fit in a 15-bit signed integer,
1178 uses a scratch registers to get a smaller offset. */
1179 if (CONST_OK_FOR_LETTER_P(frame_size, 'O'))
1180 size_rtx = GEN_INT (frame_size);
1181 else
1182 {
1183 /* We do not have any scratch registers. */
1184 gcc_assert (!interrupt_handler);
1185
1186 size_rtx = gen_rtx_REG (SImode, GPR_R9);
1187 insn = emit_move_insn (size_rtx, GEN_INT (frame_size & 0xffff0000));
1188 insn = emit_insn (gen_iorsi3 (size_rtx, size_rtx,
1189 GEN_INT (frame_size & 0x0000ffff)));
1190 /* Set R9 to point to old sp if required for access to register
1191 save area. */
1192 emit_insn (gen_addsi3 (size_rtx, size_rtx, stack_pointer_rtx));
1193 }
1194
1195 /* Restore sp if there was some possible change to it. */
1196 if (frame_pointer_needed)
1197 insn = emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
1198
1199 /* Restore the registers. */
1200 ms1_emit_save_fp (FROM_MEM_TO_PROCESSOR, current_frame_info);
1201 ms1_emit_save_regs (FROM_MEM_TO_PROCESSOR, current_frame_info);
1202
1203 /* Make stack adjustment and use scratch register if constant too
1204 large to fit as immediate. */
1205 if (frame_size)
1206 {
1207 if (CONST_OK_FOR_LETTER_P(frame_size, 'O'))
1208 /* Can handle this with simple add. */
1209 insn = emit_insn (gen_addsi3 (stack_pointer_rtx,
1210 stack_pointer_rtx,
1211 size_rtx));
1212 else
1213 /* Scratch reg R9 has the old sp value. */
1214 insn = emit_move_insn (stack_pointer_rtx,
1215 gen_rtx_REG (SImode, GPR_R9));
1216
1217 REG_NOTES (insn)
1218 = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
1219 gen_rtx_SET (VOIDmode,
1220 stack_pointer_rtx,
1221 gen_rtx_PLUS (SImode,
1222 stack_pointer_rtx,
1223 GEN_INT (frame_size))),
1224 REG_NOTES (insn));
1225 }
1226
1227 if (cfun->machine && cfun->machine->eh_stack_adjust != NULL_RTX)
1228 /* Perform the additional bump for __throw. */
1229 emit_insn (gen_addsi3 (stack_pointer_rtx,
1230 stack_pointer_rtx,
1231 cfun->machine->eh_stack_adjust));
1232
1233 /* Generate the appropriate return. */
1234 if (eh_mode == EH_EPILOGUE)
1235 {
1236 emit_jump_insn (gen_eh_return_internal ());
1237 emit_barrier ();
1238 }
1239 else if (interrupt_handler)
1240 emit_jump_insn (gen_return_interrupt_internal ());
1241 else
1242 emit_jump_insn (gen_return_internal ());
1243
1244 /* Reset state info for each function. */
1245 interrupt_handler = 0;
1246 current_frame_info = zero_frame_info;
1247 if (cfun->machine)
1248 cfun->machine->eh_stack_adjust = NULL_RTX;
1249 }
1250
1251
1252 /* Generate code for the "eh_return" pattern. */
1253 void
1254 ms1_expand_eh_return (rtx * operands)
1255 {
1256 if (GET_CODE (operands[0]) != REG
1257 || REGNO (operands[0]) != EH_RETURN_STACKADJ_REGNO)
1258 {
1259 rtx sp = EH_RETURN_STACKADJ_RTX;
1260
1261 emit_move_insn (sp, operands[0]);
1262 operands[0] = sp;
1263 }
1264
1265 emit_insn (gen_eh_epilogue (operands[0]));
1266 }
1267
1268 /* Generate code for the "eh_epilogue" pattern. */
1269 void
1270 ms1_emit_eh_epilogue (rtx * operands ATTRIBUTE_UNUSED)
1271 {
1272 cfun->machine->eh_stack_adjust = EH_RETURN_STACKADJ_RTX; /* operands[0]; */
1273 ms1_expand_epilogue (EH_EPILOGUE);
1274 }
1275
1276 /* Handle an "interrupt" attribute. */
1277 static tree
1278 ms1_handle_interrupt_attribute (tree * node,
1279 tree name,
1280 tree args ATTRIBUTE_UNUSED,
1281 int flags ATTRIBUTE_UNUSED,
1282 bool * no_add_attrs)
1283 {
1284 if (TREE_CODE (*node) != FUNCTION_DECL)
1285 {
1286 warning (OPT_Wattributes,
1287 "%qs attribute only applies to functions",
1288 IDENTIFIER_POINTER (name));
1289 *no_add_attrs = true;
1290 }
1291
1292 return NULL_TREE;
1293 }
1294
1295 /* Table of machine attributes. */
1296 const struct attribute_spec ms1_attribute_table[] =
1297 {
1298 /* name, min, max, decl?, type?, func?, handler */
1299 { "interrupt", 0, 0, false, false, false, ms1_handle_interrupt_attribute },
1300 { NULL, 0, 0, false, false, false, NULL }
1301 };
1302
1303 /* Implement INITIAL_ELIMINATION_OFFSET. */
1304 int
1305 ms1_initial_elimination_offset (int from, int to)
1306 {
1307 ms1_compute_frame_size (get_frame_size ());
1308
1309 if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
1310 return 0;
1311
1312 else if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
1313 return current_frame_info.total_size;
1314
1315 else if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
1316 return current_frame_info.total_size;
1317
1318 else
1319 gcc_unreachable ();
1320 }
1321
1322 /* Generate a compare for CODE. Return a brand-new rtx that
1323 represents the result of the compare. */
1324
1325 static rtx
1326 ms1_generate_compare (enum rtx_code code, rtx op0, rtx op1)
1327 {
1328 rtx scratch0, scratch1, const_scratch;
1329
1330 switch (code)
1331 {
1332 case GTU:
1333 case LTU:
1334 case GEU:
1335 case LEU:
1336 /* Need to adjust ranges for faking unsigned compares. */
1337 scratch0 = gen_reg_rtx (SImode);
1338 scratch1 = gen_reg_rtx (SImode);
1339 const_scratch = force_reg (SImode, GEN_INT(MS1_MIN_INT));
1340 emit_insn (gen_addsi3 (scratch0, const_scratch, op0));
1341 emit_insn (gen_addsi3 (scratch1, const_scratch, op1));
1342 break;
1343 default:
1344 scratch0 = op0;
1345 scratch1 = op1;
1346 break;
1347 }
1348
1349 /* Adjust compare operator to fake unsigned compares. */
1350 switch (code)
1351 {
1352 case GTU:
1353 code = GT; break;
1354 case LTU:
1355 code = LT; break;
1356 case GEU:
1357 code = GE; break;
1358 case LEU:
1359 code = LE; break;
1360 default:
1361 /* do nothing */
1362 break;
1363 }
1364
1365 /* Generate the actual compare. */
1366 return gen_rtx_fmt_ee (code, VOIDmode, scratch0, scratch1);
1367 }
1368
1369 /* Emit a branch of kind CODE to location LOC. */
1370
1371 void
1372 ms1_emit_cbranch (enum rtx_code code, rtx loc, rtx op0, rtx op1)
1373 {
1374 rtx condition_rtx, loc_ref;
1375
1376 if (! reg_or_0_operand (op0, SImode))
1377 op0 = copy_to_mode_reg (SImode, op0);
1378
1379 if (! reg_or_0_operand (op1, SImode))
1380 op1 = copy_to_mode_reg (SImode, op1);
1381
1382 condition_rtx = ms1_generate_compare (code, op0, op1);
1383 loc_ref = gen_rtx_LABEL_REF (VOIDmode, loc);
1384 emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
1385 gen_rtx_IF_THEN_ELSE (VOIDmode, condition_rtx,
1386 loc_ref, pc_rtx)));
1387 }
1388
1389 /* Subfunction of the following function. Update the flags of any MEM
1390 found in part of X. */
1391
1392 static void
1393 ms1_set_memflags_1 (rtx x, int in_struct_p, int volatile_p)
1394 {
1395 int i;
1396
1397 switch (GET_CODE (x))
1398 {
1399 case SEQUENCE:
1400 case PARALLEL:
1401 for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
1402 ms1_set_memflags_1 (XVECEXP (x, 0, i), in_struct_p, volatile_p);
1403 break;
1404
1405 case INSN:
1406 ms1_set_memflags_1 (PATTERN (x), in_struct_p, volatile_p);
1407 break;
1408
1409 case SET:
1410 ms1_set_memflags_1 (SET_DEST (x), in_struct_p, volatile_p);
1411 ms1_set_memflags_1 (SET_SRC (x), in_struct_p, volatile_p);
1412 break;
1413
1414 case MEM:
1415 MEM_IN_STRUCT_P (x) = in_struct_p;
1416 MEM_VOLATILE_P (x) = volatile_p;
1417 /* Sadly, we cannot use alias sets because the extra aliasing
1418 produced by the AND interferes. Given that two-byte quantities
1419 are the only thing we would be able to differentiate anyway,
1420 there does not seem to be any point in convoluting the early
1421 out of the alias check. */
1422 /* set_mem_alias_set (x, alias_set); */
1423 break;
1424
1425 default:
1426 break;
1427 }
1428 }
1429
1430 /* Look for any MEMs in the current sequence of insns and set the
1431 in-struct, unchanging, and volatile flags from the flags in REF.
1432 If REF is not a MEM, don't do anything. */
1433
1434 void
1435 ms1_set_memflags (rtx ref)
1436 {
1437 rtx insn;
1438 int in_struct_p, volatile_p;
1439
1440 if (GET_CODE (ref) != MEM)
1441 return;
1442
1443 in_struct_p = MEM_IN_STRUCT_P (ref);
1444 volatile_p = MEM_VOLATILE_P (ref);
1445
1446 /* This is only called from ms1.md, after having had something
1447 generated from one of the insn patterns. So if everything is
1448 zero, the pattern is already up-to-date. */
1449 if (! in_struct_p && ! volatile_p)
1450 return;
1451
1452 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
1453 ms1_set_memflags_1 (insn, in_struct_p, volatile_p);
1454 }
1455
1456 /* Implement SECONDARY_RELOAD_CLASS. */
1457 enum reg_class
1458 ms1_secondary_reload_class (enum reg_class class ATTRIBUTE_UNUSED,
1459 enum machine_mode mode,
1460 rtx x)
1461 {
1462 if ((mode == QImode && (!TARGET_BYTE_ACCESS)) || mode == HImode)
1463 {
1464 if (GET_CODE (x) == MEM
1465 || (GET_CODE (x) == REG && true_regnum (x) == -1)
1466 || (GET_CODE (x) == SUBREG
1467 && (GET_CODE (SUBREG_REG (x)) == MEM
1468 || (GET_CODE (SUBREG_REG (x)) == REG
1469 && true_regnum (SUBREG_REG (x)) == -1))))
1470 return GENERAL_REGS;
1471 }
1472
1473 return NO_REGS;
1474 }
1475
1476 /* Handle FUNCTION_VALUE, FUNCTION_OUTGOING_VALUE, and LIBCALL_VALUE
1477 macros. */
1478 rtx
1479 ms1_function_value (tree valtype, enum machine_mode mode, tree func_decl ATTRIBUTE_UNUSED)
1480 {
1481 if ((mode) == DImode || (mode) == DFmode)
1482 return gen_rtx_MEM (mode, gen_rtx_REG (mode, RETURN_VALUE_REGNUM));
1483
1484 if (valtype)
1485 mode = TYPE_MODE (valtype);
1486
1487 return gen_rtx_REG (mode, RETURN_VALUE_REGNUM);
1488 }
1489
1490 /* Split a move into two smaller pieces.
1491 MODE indicates the reduced mode. OPERANDS[0] is the original destination
1492 OPERANDS[1] is the original src. The new destinations are
1493 OPERANDS[2] and OPERANDS[4], while the new sources are OPERANDS[3]
1494 and OPERANDS[5]. */
1495
1496 void
1497 ms1_split_words (enum machine_mode nmode,
1498 enum machine_mode omode,
1499 rtx *operands)
1500 {
1501 rtx dl,dh; /* src/dest pieces. */
1502 rtx sl,sh;
1503 int move_high_first = 0; /* Assume no overlap. */
1504
1505 switch (GET_CODE (operands[0])) /* Dest. */
1506 {
1507 case SUBREG:
1508 case REG:
1509 if ((GET_CODE (operands[1]) == REG
1510 || GET_CODE (operands[1]) == SUBREG)
1511 && true_regnum (operands[0]) <= true_regnum (operands[1]))
1512 move_high_first = 1;
1513
1514 if (GET_CODE (operands[0]) == SUBREG)
1515 {
1516 dl = gen_rtx_SUBREG (nmode, SUBREG_REG (operands[0]),
1517 SUBREG_BYTE (operands[0]) + GET_MODE_SIZE (nmode));
1518 dh = gen_rtx_SUBREG (nmode, SUBREG_REG (operands[0]), SUBREG_BYTE (operands[0]));
1519 }
1520 else if (GET_CODE (operands[0]) == REG && ! IS_PSEUDO_P (operands[0]))
1521 {
1522 int r = REGNO (operands[0]);
1523 dh = gen_rtx_REG (nmode, r);
1524 dl = gen_rtx_REG (nmode, r + HARD_REGNO_NREGS (r, nmode));
1525 }
1526 else
1527 {
1528 dh = gen_rtx_SUBREG (nmode, operands[0], 0);
1529 dl = gen_rtx_SUBREG (nmode, operands[0], GET_MODE_SIZE (nmode));
1530 }
1531 break;
1532
1533 case MEM:
1534 switch (GET_CODE (XEXP (operands[0], 0)))
1535 {
1536 case POST_INC:
1537 case POST_DEC:
1538 gcc_unreachable ();
1539 default:
1540 dl = operand_subword (operands[0],
1541 GET_MODE_SIZE (nmode)/UNITS_PER_WORD,
1542 0, omode);
1543 dh = operand_subword (operands[0], 0, 0, omode);
1544 }
1545 break;
1546 default:
1547 gcc_unreachable ();
1548 }
1549
1550 switch (GET_CODE (operands[1]))
1551 {
1552 case REG:
1553 if (! IS_PSEUDO_P (operands[1]))
1554 {
1555 int r = REGNO (operands[1]);
1556
1557 sh = gen_rtx_REG (nmode, r);
1558 sl = gen_rtx_REG (nmode, r + HARD_REGNO_NREGS (r, nmode));
1559 }
1560 else
1561 {
1562 sh = gen_rtx_SUBREG (nmode, operands[1], 0);
1563 sl = gen_rtx_SUBREG (nmode, operands[1], GET_MODE_SIZE (nmode));
1564 }
1565 break;
1566
1567 case CONST_DOUBLE:
1568 if (operands[1] == const0_rtx)
1569 sh = sl = const0_rtx;
1570 else
1571 split_double (operands[1], & sh, & sl);
1572 break;
1573
1574 case CONST_INT:
1575 if (operands[1] == const0_rtx)
1576 sh = sl = const0_rtx;
1577 else
1578 {
1579 int vl, vh;
1580
1581 switch (nmode)
1582 {
1583 default:
1584 gcc_unreachable ();
1585 }
1586
1587 sl = GEN_INT (vl);
1588 sh = GEN_INT (vh);
1589 }
1590 break;
1591
1592 case SUBREG:
1593 sl = gen_rtx_SUBREG (nmode,
1594 SUBREG_REG (operands[1]),
1595 SUBREG_BYTE (operands[1]) + GET_MODE_SIZE (nmode));
1596 sh = gen_rtx_SUBREG (nmode,
1597 SUBREG_REG (operands[1]),
1598 SUBREG_BYTE (operands[1]));
1599 break;
1600
1601 case MEM:
1602 switch (GET_CODE (XEXP (operands[1], 0)))
1603 {
1604 case POST_DEC:
1605 case POST_INC:
1606 gcc_unreachable ();
1607 break;
1608 default:
1609 sl = operand_subword (operands[1],
1610 GET_MODE_SIZE (nmode)/UNITS_PER_WORD,
1611 0, omode);
1612 sh = operand_subword (operands[1], 0, 0, omode);
1613
1614 /* Check if the DF load is going to clobber the register
1615 used for the address, and if so make sure that is going
1616 to be the second move. */
1617 if (GET_CODE (dl) == REG
1618 && true_regnum (dl)
1619 == true_regnum (XEXP (XEXP (sl, 0 ), 0)))
1620 move_high_first = 1;
1621 }
1622 break;
1623 default:
1624 gcc_unreachable ();
1625 }
1626
1627 if (move_high_first)
1628 {
1629 operands[2] = dh;
1630 operands[3] = sh;
1631 operands[4] = dl;
1632 operands[5] = sl;
1633 }
1634 else
1635 {
1636 operands[2] = dl;
1637 operands[3] = sl;
1638 operands[4] = dh;
1639 operands[5] = sh;
1640 }
1641 return;
1642 }
1643
1644 /* Implement TARGET_MUST_PASS_IN_STACK hook. */
1645 static bool
1646 ms1_pass_in_stack (enum machine_mode mode ATTRIBUTE_UNUSED, tree type)
1647 {
1648 return (((type) != 0
1649 && (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST
1650 || TREE_ADDRESSABLE (type))));
1651 }
1652 \f
1653 /* Increment the counter for the number of loop instructions in the
1654 current function. */
1655
1656 void ms1_add_loop (void)
1657 {
1658 cfun->machine->has_loops++;
1659 }
1660
1661
1662 /* Maxium loop nesting depth. */
1663 #define MAX_LOOP_DEPTH 4
1664 /* Maxium size of a loop (allows some headroom for delayed branch slot
1665 filling. */
1666 #define MAX_LOOP_LENGTH (200 * 4)
1667
1668 /* We need to keep a vector of basic blocks */
1669 DEF_VEC_P (basic_block);
1670 DEF_VEC_ALLOC_P (basic_block,heap);
1671
1672 /* And a vector of loops */
1673 typedef struct loop_info *loop_info;
1674 DEF_VEC_P (loop_info);
1675 DEF_VEC_ALLOC_P (loop_info,heap);
1676
1677 /* Information about a loop we have found (or are in the process of
1678 finding). */
1679 struct loop_info GTY (())
1680 {
1681 /* loop number, for dumps */
1682 int loop_no;
1683
1684 /* Predecessor block of the loop. This is the one that falls into
1685 the loop and contains the initialization instruction. */
1686 basic_block predecessor;
1687
1688 /* First block in the loop. This is the one branched to by the dbnz
1689 insn. */
1690 basic_block head;
1691
1692 /* Last block in the loop (the one with the dbnz insn */
1693 basic_block tail;
1694
1695 /* The successor block of the loop. This is the one the dbnz insn
1696 falls into. */
1697 basic_block successor;
1698
1699 /* The dbnz insn. */
1700 rtx dbnz;
1701
1702 /* The initialization insn. */
1703 rtx init;
1704
1705 /* The new initialization instruction. */
1706 rtx loop_init;
1707
1708 /* The new ending instruction. */
1709 rtx loop_end;
1710
1711 /* The new label placed at the end of the loop. */
1712 rtx end_label;
1713
1714 /* The nesting depth of the loop. Set to -1 for a bad loop. */
1715 int depth;
1716
1717 /* The length of the loop. */
1718 int length;
1719
1720 /* Next loop in the graph. */
1721 struct loop_info *next;
1722
1723 /* Vector of blocks only within the loop, (excluding those within
1724 inner loops). */
1725 VEC (basic_block,heap) *blocks;
1726
1727 /* Vector of inner loops within this loop */
1728 VEC (loop_info,heap) *loops;
1729 };
1730
1731 /* Information used during loop detection. */
1732 typedef struct loop_work GTY(())
1733 {
1734 /* Basic block to be scanned. */
1735 basic_block block;
1736
1737 /* Loop it will be within. */
1738 loop_info loop;
1739 } loop_work;
1740
1741 /* Work list. */
1742 DEF_VEC_O (loop_work);
1743 DEF_VEC_ALLOC_O (loop_work,heap);
1744
1745 /* Determine the nesting and length of LOOP. Return false if the loop
1746 is bad. */
1747
1748 static bool
1749 ms1_loop_nesting (loop_info loop)
1750 {
1751 loop_info inner;
1752 unsigned ix;
1753 int inner_depth = 0;
1754
1755 if (!loop->depth)
1756 {
1757 /* Make sure we only have one entry point. */
1758 if (EDGE_COUNT (loop->head->preds) == 2)
1759 {
1760 loop->predecessor = EDGE_PRED (loop->head, 0)->src;
1761 if (loop->predecessor == loop->tail)
1762 /* We wanted the other predecessor. */
1763 loop->predecessor = EDGE_PRED (loop->head, 1)->src;
1764
1765 /* We can only place a loop insn on a fall through edge of a
1766 single exit block. */
1767 if (EDGE_COUNT (loop->predecessor->succs) != 1
1768 || !(EDGE_SUCC (loop->predecessor, 0)->flags & EDGE_FALLTHRU))
1769 loop->predecessor = NULL;
1770 }
1771
1772 /* Mark this loop as bad for now. */
1773 loop->depth = -1;
1774 if (loop->predecessor)
1775 {
1776 for (ix = 0; VEC_iterate (loop_info, loop->loops, ix++, inner);)
1777 {
1778 if (!inner->depth)
1779 ms1_loop_nesting (inner);
1780
1781 if (inner->depth < 0)
1782 {
1783 inner_depth = -1;
1784 break;
1785 }
1786
1787 if (inner_depth < inner->depth)
1788 inner_depth = inner->depth;
1789 loop->length += inner->length;
1790 }
1791
1792 /* Set the proper loop depth, if it was good. */
1793 if (inner_depth >= 0)
1794 loop->depth = inner_depth + 1;
1795 }
1796 }
1797 return (loop->depth > 0
1798 && loop->predecessor
1799 && loop->depth < MAX_LOOP_DEPTH
1800 && loop->length < MAX_LOOP_LENGTH);
1801 }
1802
1803 /* Determine the length of block BB. */
1804
1805 static int
1806 ms1_block_length (basic_block bb)
1807 {
1808 int length = 0;
1809 rtx insn;
1810
1811 for (insn = BB_HEAD (bb);
1812 insn != NEXT_INSN (BB_END (bb));
1813 insn = NEXT_INSN (insn))
1814 {
1815 if (!INSN_P (insn))
1816 continue;
1817 if (CALL_P (insn))
1818 {
1819 /* Calls are not allowed in loops. */
1820 length = MAX_LOOP_LENGTH + 1;
1821 break;
1822 }
1823
1824 length += get_attr_length (insn);
1825 }
1826 return length;
1827 }
1828
1829 /* Scan the blocks of LOOP (and its inferiors) looking for uses of
1830 REG. Return true, if we find any. Don't count the loop's dbnz
1831 insn if it matches DBNZ. */
1832
1833 static bool
1834 ms1_scan_loop (loop_info loop, rtx reg, rtx dbnz)
1835 {
1836 unsigned ix;
1837 loop_info inner;
1838 basic_block bb;
1839
1840 for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, bb); ix++)
1841 {
1842 rtx insn;
1843
1844 for (insn = BB_HEAD (bb);
1845 insn != NEXT_INSN (BB_END (bb));
1846 insn = NEXT_INSN (insn))
1847 {
1848 if (!INSN_P (insn))
1849 continue;
1850 if (insn == dbnz)
1851 continue;
1852 if (reg_mentioned_p (reg, PATTERN (insn)))
1853 return true;
1854 }
1855 }
1856 for (ix = 0; VEC_iterate (loop_info, loop->loops, ix, inner); ix++)
1857 if (ms1_scan_loop (inner, reg, NULL_RTX))
1858 return true;
1859
1860 return false;
1861 }
1862
1863 /* MS2 has a loop instruction which needs to be placed just before the
1864 loop. It indicates the end of the loop and specifies the number of
1865 loop iterations. It can be nested with an automatically maintained
1866 stack of counter and end address registers. It's an ideal
1867 candidate for doloop. Unfortunately, gcc presumes that loops
1868 always end with an explicit instriction, and the doloop_begin
1869 instruction is not a flow control instruction so it can be
1870 scheduled earlier than just before the start of the loop. To make
1871 matters worse, the optimization pipeline can duplicate loop exit
1872 and entrance blocks and fails to track abnormally exiting loops.
1873 Thus we cannot simply use doloop.
1874
1875 What we do is emit a dbnz pattern for the doloop optimization, and
1876 let that be optimized as normal. Then in machine dependent reorg
1877 we have to repeat the loop searching algorithm. We use the
1878 flow graph to find closed loops ending in a dbnz insn. We then try
1879 and convert it to use the loop instruction. The conditions are,
1880
1881 * the loop has no abnormal exits, duplicated end conditions or
1882 duplicated entrance blocks
1883
1884 * the loop counter register is only used in the dbnz instruction
1885 within the loop
1886
1887 * we can find the instruction setting the initial value of the loop
1888 counter
1889
1890 * the loop is not executed more than 65535 times. (This might be
1891 changed to 2^32-1, and would therefore allow variable initializers.)
1892
1893 * the loop is not nested more than 4 deep 5) there are no
1894 subroutine calls in the loop. */
1895
1896 static void
1897 ms1_reorg_loops (FILE *dump_file)
1898 {
1899 basic_block bb;
1900 loop_info loops = NULL;
1901 loop_info loop;
1902 int nloops = 0;
1903 unsigned dwork = 0;
1904 VEC (loop_work,heap) *works = VEC_alloc (loop_work,heap,20);
1905 loop_work *work;
1906 edge e;
1907 edge_iterator ei;
1908 bool replaced = false;
1909
1910 /* Find all the possible loop tails. This means searching for every
1911 dbnz instruction. For each one found, create a loop_info
1912 structure and add the head block to the work list. */
1913 FOR_EACH_BB (bb)
1914 {
1915 rtx tail = BB_END (bb);
1916
1917 while (GET_CODE (tail) == NOTE)
1918 tail = PREV_INSN (tail);
1919
1920 bb->aux = NULL;
1921 if (recog_memoized (tail) == CODE_FOR_decrement_and_branch_until_zero)
1922 {
1923 /* A possible loop end */
1924
1925 loop = XNEW (struct loop_info);
1926 loop->next = loops;
1927 loops = loop;
1928 loop->tail = bb;
1929 loop->head = BRANCH_EDGE (bb)->dest;
1930 loop->successor = FALLTHRU_EDGE (bb)->dest;
1931 loop->predecessor = NULL;
1932 loop->dbnz = tail;
1933 loop->depth = 0;
1934 loop->length = ms1_block_length (bb);
1935 loop->blocks = VEC_alloc (basic_block, heap, 20);
1936 VEC_quick_push (basic_block, loop->blocks, bb);
1937 loop->loops = NULL;
1938 loop->loop_no = nloops++;
1939
1940 loop->init = loop->end_label = NULL_RTX;
1941 loop->loop_init = loop->loop_end = NULL_RTX;
1942
1943 work = VEC_safe_push (loop_work, heap, works, NULL);
1944 work->block = loop->head;
1945 work->loop = loop;
1946
1947 bb->aux = loop;
1948
1949 if (dump_file)
1950 {
1951 fprintf (dump_file, ";; potential loop %d ending at\n",
1952 loop->loop_no);
1953 print_rtl_single (dump_file, tail);
1954 }
1955 }
1956 }
1957
1958 /* Now find all the closed loops.
1959 until work list empty,
1960 if block's auxptr is set
1961 if != loop slot
1962 if block's loop's start != block
1963 mark loop as bad
1964 else
1965 append block's loop's fallthrough block to worklist
1966 increment this loop's depth
1967 else if block is exit block
1968 mark loop as bad
1969 else
1970 set auxptr
1971 for each target of block
1972 add to worklist */
1973 while (VEC_iterate (loop_work, works, dwork++, work))
1974 {
1975 loop = work->loop;
1976 bb = work->block;
1977 if (bb == EXIT_BLOCK_PTR)
1978 /* We've reached the exit block. The loop must be bad. */
1979 loop->depth = -1;
1980 else if (!bb->aux)
1981 {
1982 /* We've not seen this block before. Add it to the loop's
1983 list and then add each successor to the work list. */
1984 bb->aux = loop;
1985 loop->length += ms1_block_length (bb);
1986 VEC_safe_push (basic_block, heap, loop->blocks, bb);
1987 FOR_EACH_EDGE (e, ei, bb->succs)
1988 {
1989 if (!VEC_space (loop_work, works, 1))
1990 {
1991 if (dwork)
1992 {
1993 VEC_block_remove (loop_work, works, 0, dwork);
1994 dwork = 0;
1995 }
1996 else
1997 VEC_reserve (loop_work, heap, works, 1);
1998 }
1999 work = VEC_quick_push (loop_work, works, NULL);
2000 work->block = EDGE_SUCC (bb, ei.index)->dest;
2001 work->loop = loop;
2002 }
2003 }
2004 else if (bb->aux != loop)
2005 {
2006 /* We've seen this block in a different loop. If it's not
2007 the other loop's head, then this loop must be bad.
2008 Otherwise, the other loop might be a nested loop, so
2009 continue from that loop's successor. */
2010 loop_info other = bb->aux;
2011
2012 if (other->head != bb)
2013 loop->depth = -1;
2014 else
2015 {
2016 VEC_safe_push (loop_info, heap, loop->loops, other);
2017 work = VEC_safe_push (loop_work, heap, works, NULL);
2018 work->loop = loop;
2019 work->block = other->successor;
2020 }
2021 }
2022 }
2023 VEC_free (loop_work, heap, works);
2024
2025 /* Now optimize the loops. */
2026 for (loop = loops; loop; loop = loop->next)
2027 {
2028 rtx iter_reg, insn, init_insn;
2029 rtx init_val, loop_end, loop_init, end_label, head_label;
2030
2031 if (!ms1_loop_nesting (loop))
2032 {
2033 if (dump_file)
2034 fprintf (dump_file, ";; loop %d is bad\n", loop->loop_no);
2035 continue;
2036 }
2037
2038 /* Get the loop iteration register. */
2039 iter_reg = SET_DEST (XVECEXP (PATTERN (loop->dbnz), 0, 1));
2040
2041 if (!REG_P (iter_reg))
2042 {
2043 /* Spilled */
2044 if (dump_file)
2045 fprintf (dump_file, ";; loop %d has spilled iteration count\n",
2046 loop->loop_no);
2047 continue;
2048 }
2049
2050 /* Look for the initializing insn */
2051 init_insn = NULL_RTX;
2052 for (insn = BB_END (loop->predecessor);
2053 insn != PREV_INSN (BB_HEAD (loop->predecessor));
2054 insn = PREV_INSN (insn))
2055 {
2056 if (!INSN_P (insn))
2057 continue;
2058 if (reg_mentioned_p (iter_reg, PATTERN (insn)))
2059 {
2060 rtx set = single_set (insn);
2061
2062 if (set && rtx_equal_p (iter_reg, SET_DEST (set)))
2063 init_insn = insn;
2064 break;
2065 }
2066 }
2067
2068 if (!init_insn)
2069 {
2070 if (dump_file)
2071 fprintf (dump_file, ";; loop %d has no initializer\n",
2072 loop->loop_no);
2073 continue;
2074 }
2075 if (dump_file)
2076 {
2077 fprintf (dump_file, ";; loop %d initialized by\n",
2078 loop->loop_no);
2079 print_rtl_single (dump_file, init_insn);
2080 }
2081
2082 init_val = PATTERN (init_insn);
2083 if (GET_CODE (init_val) == SET)
2084 init_val = SET_SRC (init_val);
2085 if (GET_CODE (init_val) != CONST_INT || INTVAL (init_val) >= 65535)
2086 {
2087 if (dump_file)
2088 fprintf (dump_file, ";; loop %d has complex initializer\n",
2089 loop->loop_no);
2090 continue;
2091 }
2092
2093 /* Scan all the blocks to make sure they don't use iter_reg. */
2094 if (ms1_scan_loop (loop, iter_reg, loop->dbnz))
2095 {
2096 if (dump_file)
2097 fprintf (dump_file, ";; loop %d uses iterator\n",
2098 loop->loop_no);
2099 continue;
2100 }
2101
2102 /* The loop is good for replacement. */
2103
2104 /* loop is 1 based, dbnz is zero based. */
2105 init_val = GEN_INT (INTVAL (init_val) + 1);
2106
2107 iter_reg = gen_rtx_REG (SImode, LOOP_FIRST + loop->depth - 1);
2108 end_label = gen_label_rtx ();
2109 head_label = XEXP (SET_SRC (XVECEXP (PATTERN (loop->dbnz), 0, 0)), 1);
2110 loop_end = gen_loop_end (iter_reg, head_label);
2111 loop_init = gen_loop_init (iter_reg, init_val, end_label);
2112 loop->init = init_insn;
2113 loop->end_label = end_label;
2114 loop->loop_init = loop_init;
2115 loop->loop_end = loop_end;
2116 replaced = true;
2117
2118 if (dump_file)
2119 {
2120 fprintf (dump_file, ";; replacing loop %d initializer with\n",
2121 loop->loop_no);
2122 print_rtl_single (dump_file, loop->loop_init);
2123 fprintf (dump_file, ";; replacing loop %d terminator with\n",
2124 loop->loop_no);
2125 print_rtl_single (dump_file, loop->loop_end);
2126 }
2127 }
2128
2129 /* Now apply the optimizations. Do it this way so we don't mess up
2130 the flow graph half way through. */
2131 for (loop = loops; loop; loop = loop->next)
2132 if (loop->loop_init)
2133 {
2134 emit_jump_insn_after (loop->loop_init, BB_END (loop->predecessor));
2135 delete_insn (loop->init);
2136 emit_label_before (loop->end_label, loop->dbnz);
2137 emit_jump_insn_before (loop->loop_end, loop->dbnz);
2138 delete_insn (loop->dbnz);
2139 }
2140
2141 /* Free up the loop structures */
2142 while (loops)
2143 {
2144 loop = loops;
2145 loops = loop->next;
2146 VEC_free (loop_info, heap, loop->loops);
2147 VEC_free (basic_block, heap, loop->blocks);
2148 XDELETE (loop);
2149 }
2150
2151 if (replaced && dump_file)
2152 {
2153 fprintf (dump_file, ";; Replaced loops\n");
2154 print_rtl (dump_file, get_insns ());
2155 }
2156 }
2157
2158 /* Structures to hold branch information during reorg. */
2159 typedef struct branch_info
2160 {
2161 rtx insn; /* The branch insn. */
2162
2163 struct branch_info *next;
2164 } branch_info;
2165
2166 typedef struct label_info
2167 {
2168 rtx label; /* The label. */
2169 branch_info *branches; /* branches to this label. */
2170 struct label_info *next;
2171 } label_info;
2172
2173 /* Chain of labels found in current function, used during reorg. */
2174 static label_info *ms1_labels;
2175
2176 /* If *X is a label, add INSN to the list of branches for that
2177 label. */
2178
2179 static int
2180 ms1_add_branches (rtx *x, void *insn)
2181 {
2182 if (GET_CODE (*x) == LABEL_REF)
2183 {
2184 branch_info *branch = xmalloc (sizeof (*branch));
2185 rtx label = XEXP (*x, 0);
2186 label_info *info;
2187
2188 for (info = ms1_labels; info; info = info->next)
2189 if (info->label == label)
2190 break;
2191
2192 if (!info)
2193 {
2194 info = xmalloc (sizeof (*info));
2195 info->next = ms1_labels;
2196 ms1_labels = info;
2197
2198 info->label = label;
2199 info->branches = NULL;
2200 }
2201
2202 branch->next = info->branches;
2203 info->branches = branch;
2204 branch->insn = insn;
2205 }
2206 return 0;
2207 }
2208
2209 /* If BRANCH has a filled delay slot, check if INSN is dependent upon
2210 it. If so, undo the delay slot fill. Returns the next insn, if
2211 we patch out the branch. Returns the branch insn, if we cannot
2212 patch out the branch (due to anti-dependency in the delay slot).
2213 In that case, the caller must insert nops at the branch target. */
2214
2215 static rtx
2216 ms1_check_delay_slot (rtx branch, rtx insn)
2217 {
2218 rtx slot;
2219 rtx tmp;
2220 rtx p;
2221 rtx jmp;
2222
2223 gcc_assert (GET_CODE (PATTERN (branch)) == SEQUENCE);
2224 if (INSN_DELETED_P (branch))
2225 return NULL_RTX;
2226 slot = XVECEXP (PATTERN (branch), 0, 1);
2227
2228 tmp = PATTERN (insn);
2229 note_stores (PATTERN (slot), insn_dependent_p_1, &tmp);
2230 if (tmp)
2231 /* Not dependent. */
2232 return NULL_RTX;
2233
2234 /* Undo the delay slot. */
2235 jmp = XVECEXP (PATTERN (branch), 0, 0);
2236
2237 tmp = PATTERN (jmp);
2238 note_stores (PATTERN (slot), insn_dependent_p_1, &tmp);
2239 if (!tmp)
2240 /* Anti dependent. */
2241 return branch;
2242
2243 p = PREV_INSN (branch);
2244 NEXT_INSN (p) = slot;
2245 PREV_INSN (slot) = p;
2246 NEXT_INSN (slot) = jmp;
2247 PREV_INSN (jmp) = slot;
2248 NEXT_INSN (jmp) = branch;
2249 PREV_INSN (branch) = jmp;
2250 XVECEXP (PATTERN (branch), 0, 0) = NULL_RTX;
2251 XVECEXP (PATTERN (branch), 0, 1) = NULL_RTX;
2252 delete_insn (branch);
2253 return jmp;
2254 }
2255
2256 /* Insert nops to satisfy pipeline constraints. We only deal with ms2
2257 constraints here. Earlier CPUs are dealt with by inserting nops with
2258 final_prescan (but that can lead to inferior code, and is
2259 impractical with ms2's JAL hazard).
2260
2261 ms2 dynamic constraints
2262 1) a load and a following use must be separated by one insn
2263 2) an insn and a following dependent call must be separated by two insns
2264
2265 only arith insns are placed in delay slots so #1 cannot happen with
2266 a load in a delay slot. #2 can happen with an arith insn in the
2267 delay slot. */
2268
2269 static void
2270 ms1_reorg_hazard (void)
2271 {
2272 rtx insn, next;
2273
2274 /* Find all the branches */
2275 for (insn = get_insns ();
2276 insn;
2277 insn = NEXT_INSN (insn))
2278 {
2279 rtx jmp;
2280
2281 if (!INSN_P (insn))
2282 continue;
2283
2284 jmp = PATTERN (insn);
2285
2286 if (GET_CODE (jmp) != SEQUENCE)
2287 /* If it's not got a filled delay slot, then it can't
2288 conflict. */
2289 continue;
2290
2291 jmp = XVECEXP (jmp, 0, 0);
2292
2293 if (recog_memoized (jmp) == CODE_FOR_tablejump)
2294 for (jmp = XEXP (XEXP (XVECEXP (PATTERN (jmp), 0, 1), 0), 0);
2295 !JUMP_TABLE_DATA_P (jmp);
2296 jmp = NEXT_INSN (jmp))
2297 continue;
2298
2299 for_each_rtx (&PATTERN (jmp), ms1_add_branches, insn);
2300 }
2301
2302 /* Now scan for dependencies. */
2303 for (insn = get_insns ();
2304 insn && !INSN_P (insn);
2305 insn = NEXT_INSN (insn))
2306 continue;
2307
2308 for (;
2309 insn;
2310 insn = next)
2311 {
2312 rtx jmp, tmp;
2313 enum attr_type attr;
2314
2315 gcc_assert (INSN_P (insn) && !INSN_DELETED_P (insn));
2316 for (next = NEXT_INSN (insn);
2317 next && !INSN_P (next);
2318 next = NEXT_INSN (next))
2319 continue;
2320
2321 jmp = insn;
2322 if (GET_CODE (PATTERN (insn)) == SEQUENCE)
2323 jmp = XVECEXP (PATTERN (insn), 0, 0);
2324
2325 attr = recog_memoized (jmp) >= 0 ? get_attr_type (jmp) : TYPE_UNKNOWN;
2326
2327 if (next && attr == TYPE_LOAD)
2328 {
2329 /* A load. See if NEXT is dependent, and if so insert a
2330 nop. */
2331
2332 tmp = PATTERN (next);
2333 if (GET_CODE (tmp) == SEQUENCE)
2334 tmp = PATTERN (XVECEXP (tmp, 0, 0));
2335 note_stores (PATTERN (insn), insn_dependent_p_1, &tmp);
2336 if (!tmp)
2337 emit_insn_after (gen_nop (), insn);
2338 }
2339
2340 if (attr == TYPE_CALL)
2341 {
2342 /* A call. Make sure we're not dependent on either of the
2343 previous two dynamic instructions. */
2344 int nops = 0;
2345 int count;
2346 rtx prev = insn;
2347 rtx rescan = NULL_RTX;
2348
2349 for (count = 2; count && !nops;)
2350 {
2351 int type;
2352
2353 prev = PREV_INSN (prev);
2354 if (!prev)
2355 {
2356 /* If we reach the start of the function, we must
2357 presume the caller set the address in the delay
2358 slot of the call instruction. */
2359 nops = count;
2360 break;
2361 }
2362
2363 if (BARRIER_P (prev))
2364 break;
2365 if (LABEL_P (prev))
2366 {
2367 /* Look at branches to this label. */
2368 label_info *label;
2369 branch_info *branch;
2370
2371 for (label = ms1_labels;
2372 label;
2373 label = label->next)
2374 if (label->label == prev)
2375 {
2376 for (branch = label->branches;
2377 branch;
2378 branch = branch->next)
2379 {
2380 tmp = ms1_check_delay_slot (branch->insn, jmp);
2381
2382 if (tmp == branch->insn)
2383 {
2384 nops = count;
2385 break;
2386 }
2387
2388 if (tmp && branch->insn == next)
2389 rescan = tmp;
2390 }
2391 break;
2392 }
2393 continue;
2394 }
2395 if (!INSN_P (prev))
2396 continue;
2397
2398 if (GET_CODE (PATTERN (prev)) == SEQUENCE)
2399 {
2400 /* Look at the delay slot. */
2401 tmp = ms1_check_delay_slot (prev, jmp);
2402 if (tmp == prev)
2403 nops = count;
2404 break;
2405 }
2406
2407 type = (INSN_CODE (prev) >= 0 ? get_attr_type (prev)
2408 : TYPE_COMPLEX);
2409 if (type == TYPE_CALL || type == TYPE_BRANCH)
2410 break;
2411
2412 if (type == TYPE_LOAD
2413 || type == TYPE_ARITH
2414 || type == TYPE_COMPLEX)
2415 {
2416 tmp = PATTERN (jmp);
2417 note_stores (PATTERN (prev), insn_dependent_p_1, &tmp);
2418 if (!tmp)
2419 {
2420 nops = count;
2421 break;
2422 }
2423 }
2424
2425 if (INSN_CODE (prev) >= 0)
2426 {
2427 rtx set = single_set (prev);
2428
2429 /* A noop set will get deleted in a later split pass,
2430 so we can't count on it for hazard avoidance. */
2431 if (!set || !set_noop_p (set))
2432 count--;
2433 }
2434 }
2435
2436 if (rescan)
2437 for (next = NEXT_INSN (rescan);
2438 next && !INSN_P (next);
2439 next = NEXT_INSN (next))
2440 continue;
2441 while (nops--)
2442 emit_insn_before (gen_nop (), insn);
2443 }
2444 }
2445
2446 /* Free the data structures. */
2447 while (ms1_labels)
2448 {
2449 label_info *label = ms1_labels;
2450 branch_info *branch, *next;
2451
2452 ms1_labels = label->next;
2453 for (branch = label->branches; branch; branch = next)
2454 {
2455 next = branch->next;
2456 free (branch);
2457 }
2458 free (label);
2459 }
2460 }
2461
2462 /* Fixup the looping instructions, do delayed branch scheduling, fixup
2463 scheduling hazards. */
2464
2465 static void
2466 ms1_machine_reorg (void)
2467 {
2468 if (cfun->machine->has_loops)
2469 ms1_reorg_loops (dump_file);
2470
2471 if (ms1_flag_delayed_branch)
2472 dbr_schedule (get_insns (), dump_file);
2473
2474 if (ms1_cpu == PROCESSOR_MS2)
2475 ms1_reorg_hazard ();
2476 }
2477 \f
2478 /* Initialize the GCC target structure. */
2479 const struct attribute_spec ms1_attribute_table[];
2480
2481 #undef TARGET_ATTRIBUTE_TABLE
2482 #define TARGET_ATTRIBUTE_TABLE ms1_attribute_table
2483 #undef TARGET_STRUCT_VALUE_RTX
2484 #define TARGET_STRUCT_VALUE_RTX ms1_struct_value_rtx
2485 #undef TARGET_PROMOTE_PROTOTYPES
2486 #define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true
2487 #undef TARGET_PASS_BY_REFERENCE
2488 #define TARGET_PASS_BY_REFERENCE ms1_pass_by_reference
2489 #undef TARGET_MUST_PASS_IN_STACK
2490 #define TARGET_MUST_PASS_IN_STACK ms1_pass_in_stack
2491 #undef TARGET_ARG_PARTIAL_BYTES
2492 #define TARGET_ARG_PARTIAL_BYTES ms1_arg_partial_bytes
2493 #undef TARGET_MACHINE_DEPENDENT_REORG
2494 #define TARGET_MACHINE_DEPENDENT_REORG ms1_machine_reorg
2495
2496 struct gcc_target targetm = TARGET_INITIALIZER;
2497 \f
2498 #include "gt-ms1.h"