Start development on 386BSD 0.0
[unix-history] / .ref-BSD-4_3_Net_2 / usr / src / usr.bin / gcc / cc1 / config / out-mips.c
CommitLineData
703c7c2d
C
1/* Subroutines for insn-output.c for MIPS
2 Contributed by A. Lichnewsky, lich@inria.inria.fr.
3 Changes by Michael Meissner, meissner@osf.org.
4 Copyright (C) 1989, 1990 Free Software Foundation, Inc.
5
6This file is part of GNU CC.
7
8GNU CC is free software; you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation; either version 1, or (at your option)
11any later version.
12
13GNU CC is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with GNU CC; see the file COPYING. If not, write to
20the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
21
22
23#include <stdio.h>
24#include "tree.h"
25#include "flags.h"
26
27extern void debug_rtx ();
28extern void abort_with_insn ();
29
30extern FILE *asm_out_file;
31extern tree current_function_decl;
32
33/* Global variables for machine-dependent things. */
34
35char *reg_numchar[] = REGISTER_NUMCHAR;
36
37/* Threshold for data being put into the small data/bss area, instead
38 of the normal data area (references to the small data/bss area take
39 1 instruction, and use the global pointer, references to the normal
40 data area takes 2 instructions). */
41int mips_section_threshold = -1;
42
43/* Count the number of .file directives, so that .loc is up to date. */
44int num_source_filenames = 0;
45
46/* Count the number of words that are pushed to pass arguments. */
47int stack_args_pushed = 0;
48
49/* # bytes for args preallocated by function_prolog. */
50int stack_args_preallocated = 0;
51
52/* Count of the number of functions created so far, in order to make
53 unique labels for omitting the frame pointer. */
54int number_functions_processed = 0;
55
56/* Count the number of sdb related labels are generated (to find block
57 start and end boundaries). */
58int sdb_label_count = 0;
59
60/* Next label # for each statment for Silicon Graphics IRIS systems. */
61int sym_lineno = 0;
62
63/* Non-zero if inside of a function, because the stupid MIPS asm can't
64 handle .files inside of functions. */
65int inside_function = 0;
66
67/* String to be used for the unique name given to the difference between
68 the stack pointer and frame pointer when the frame pointer is to be
69 omitted. */
70char *sp_fp_difference = 0;
71
72/* Files to separate the text and the data output, so that all of the data
73 can be emitted before the text, which will mean that the assembler will
74 generate smaller code, based on the global pointer. */
75FILE *asm_out_data_file;
76FILE *asm_out_text_file;
77
78/* Linked list of all externals that are to be emitted when optimizing
79 for the global pointer if they haven't been declared by the end of
80 the program with an appropriate .comm or initialization. */
81
82struct extern_list {
83 struct extern_list *next; /* next external */
84 char *name; /* name of the external */
85 int size; /* size in bytes */
86} *extern_head = 0;
87
88/* Name of the current function. */
89char *current_function_name;
90
91/* Size of the frame allocated for this function. */
92int current_function_total_framesize;
93
94/* Number of bytes used to hold saved registers. */
95int current_function_saved_reg_size;
96\f
97/* Return truth value of whether OP can be used as an operands
98 where a register or 16 bit unsigned integer is needed. */
99
100int
101uns_arith_operand (op, mode)
102 rtx op;
103 enum machine_mode mode;
104{
105 return (register_operand (op, mode)
106 || (GET_CODE (op) == CONST_INT && SMALL_INT_UNSIGNED (op)));
107}
108
109/* Return truth value of whether OP can be used as an operands
110 where a 16 bit integer is needed */
111
112int
113arith_operand (op, mode)
114 rtx op;
115 enum machine_mode mode;
116{
117 return (register_operand (op, mode)
118 || (GET_CODE (op) == CONST_INT && SMALL_INT (op)));
119}
120
121/* Return truth value of whether OP can be used as an operand in a two
122 address arithmetic insn (such as set 123456,%o4) of mode MODE. */
123
124int
125arith32_operand (op, mode)
126 rtx op;
127 enum machine_mode mode;
128{
129 return (register_operand (op, mode) || GET_CODE (op) == CONST_INT);
130}
131
132/* Return truth value of whether OP is a integer which fits in 16 bits */
133
134int
135small_int (op, mode)
136 rtx op;
137 enum machine_mode mode;
138{
139 return (GET_CODE (op) == CONST_INT && SMALL_INT (op));
140}
141
142\f
143/* Argument support functions. */
144
145/* Initialize CUMULATIVE_ARGS for a function. */
146
147void
148init_cumulative_args (cum, fntype)
149 CUMULATIVE_ARGS cum; /* argument info to initialize */
150 tree fntype; /* tree ptr for function decl */
151{
152 tree param, next_param;
153
154 if (TARGET_DEBUGE_MODE)
155 {
156 fprintf (stderr, "\ninit_cumulative_args\n");
157 if (fntype != (tree)0)
158 {
159 putc ('\n', stderr);
160 debug_tree (fntype);
161 putc ('\n', stderr);
162 }
163 }
164
165 cum->gp_reg_found = 0;
166 cum->arg_number = 0;
167 cum->arg_words = 0;
168
169 /* Determine if this function has variable arguments. This is
170 indicated by the last argument being 'void_type_mode' if there
171 are no variable arguments. The standard MIPS calling sequence
172 passes all arguments in the general purpose registers in this
173 case. */
174
175 for (param = (fntype) ? TYPE_ARG_TYPES (fntype) : 0;
176 param != (tree)0;
177 param = next_param)
178 {
179 next_param = TREE_CHAIN (param);
180 if (next_param == (tree)0 && TREE_VALUE (param) != void_type_node)
181 cum->gp_reg_found = 1;
182 }
183
184 /* Determine if the function is returning a structure, if so,
185 advance by one argument. */
186
187 if (fntype
188 && (TREE_CODE (fntype) == FUNCTION_TYPE || TREE_CODE (fntype) == METHOD_TYPE)
189 && TREE_TYPE (fntype) != 0)
190 {
191 tree ret_type = TREE_TYPE (fntype);
192 enum tree_code ret_code = TREE_CODE (ret_type);
193
194 if (ret_code == RECORD_TYPE || ret_code == UNION_TYPE)
195 {
196 cum->gp_reg_found = 1;
197 cum->arg_number = 1;
198 cum->arg_words = 1;
199 }
200 }
201}
202
203/* Advance the argument to the next argument position. */
204
205void
206function_arg_advance (cum, mode, type, named)
207 CUMULATIVE_ARGS cum; /* current arg information */
208 enum machine_mode mode; /* current arg mode */
209 tree type; /* type of the argument or 0 if lib support */
210{
211 if (TARGET_DEBUGE_MODE)
212 fprintf (stderr,
213 "function_adv( {gp reg found = %d, arg # = %2d, words = %2d}, %4s, 0x%.8x, %d )\n",
214 cum->gp_reg_found, cum->arg_number, cum->arg_words, GET_MODE_NAME (mode),
215 type, named);
216
217 cum->arg_number++;
218 switch (mode)
219 {
220 default:
221 error ("Illegal mode given to function_arg_advance");
222 break;
223
224 case VOIDmode:
225 break;
226
227 case BLKmode:
228 cum->gp_reg_found = 1;
229 cum->arg_words += (int_size_in_bytes (type) + 3) / 4;
230 break;
231
232 case SFmode:
233 cum->arg_words++;
234 break;
235
236 case DFmode:
237 cum->arg_words += 2;
238 break;
239
240 case DImode:
241 cum->gp_reg_found = 1;
242 cum->arg_words += 2;
243 break;
244
245 case QImode:
246 case HImode:
247 case SImode:
248 cum->gp_reg_found = 1;
249 cum->arg_words++;
250 break;
251 }
252}
253
254/* Return a RTL expression containing the register for the given mode,
255 or 0 if the argument is too be passed on the stack. */
256
257struct rtx_def *
258function_arg (cum, mode, type, named)
259 CUMULATIVE_ARGS cum; /* current arg information */
260 enum machine_mode mode; /* current arg mode */
261 tree type; /* type of the argument or 0 if lib support */
262 int named; /* != 0 for normal args, == 0 for ... args */
263{
264 int regbase = -1;
265 int bias = 0;
266
267 if (TARGET_DEBUGE_MODE)
268 fprintf (stderr,
269 "function_arg( {gp reg found = %d, arg # = %2d, words = %2d}, %4s, 0x%.8x, %d ) = ",
270 cum->gp_reg_found, cum->arg_number, cum->arg_words, GET_MODE_NAME (mode),
271 type, named);
272
273 switch (mode)
274 {
275 default:
276 error ("Illegal mode given to function_arg");
277 break;
278
279 case SFmode:
280 if (cum->gp_reg_found || cum->arg_number >= 2)
281 regbase = GP_ARG_FIRST;
282 else {
283 regbase = FP_ARG_FIRST;
284 if (cum->arg_words == 1) /* first arg was float */
285 bias = 1; /* use correct reg */
286 }
287
288 break;
289
290 case DFmode:
291 cum->arg_words += (cum->arg_words & 1);
292 regbase = (cum->gp_reg_found) ? GP_ARG_FIRST : FP_ARG_FIRST;
293 break;
294
295 case VOIDmode:
296 case BLKmode:
297 case QImode:
298 case HImode:
299 case SImode:
300 case DImode:
301 regbase = GP_ARG_FIRST;
302 break;
303 }
304
305 if (cum->arg_words >= MAX_ARGS_IN_REGISTERS)
306 {
307 if (TARGET_DEBUGE_MODE)
308 fprintf (stderr, "<stack>\n");
309
310 return 0;
311 }
312
313 if (regbase == -1)
314 abort ();
315
316 if (TARGET_DEBUGE_MODE)
317 fprintf (stderr, "%s\n", reg_numchar[ regbase + cum->arg_number + bias ]);
318
319 return gen_rtx (REG, mode, regbase + cum->arg_words + bias);
320}
321
322
323int
324function_arg_partial_nregs (cum, mode, type, named)
325 CUMULATIVE_ARGS cum; /* current arg information */
326 enum machine_mode mode; /* current arg mode */
327 tree type; /* type of the argument or 0 if lib support */
328 int named; /* != 0 for normal args, == 0 for ... args */
329{
330 if (mode == BLKmode && cum->arg_number < MAX_ARGS_IN_REGISTERS)
331 {
332 int words = (int_size_in_bytes (type) + 3) / 4;
333
334 if (words + cum->arg_words < MAX_ARGS_IN_REGISTERS)
335 return 0; /* structure fits in registers */
336
337 if (TARGET_DEBUGE_MODE)
338 fprintf (stderr, "function_arg_partial_nregs = %d\n",
339 MAX_ARGS_IN_REGISTERS - cum->arg_words);
340
341 return MAX_ARGS_IN_REGISTERS - cum->arg_words;
342 }
343
344 else if (mode == DImode && cum->arg_number == MAX_ARGS_IN_REGISTERS-1)
345 {
346 if (TARGET_DEBUGE_MODE)
347 fprintf (stderr, "function_arg_partial_nregs = 1\n");
348
349 return 1;
350 }
351
352 return 0;
353}
354
355\f
356/* Routines to merge the compare and branch operators into a single entity. */
357
358static rtx branch_cmp_op[2];
359static enum machine_mode branch_cmp_mode;
360
361/* Save the mode and operands on the current compare operator. */
362
363void
364compare_collect (mode, op0, op1)
365 enum machine_mode mode;
366 rtx op0;
367 rtx op1;
368{
369 if (TARGET_DEBUGD_MODE)
370 {
371 fprintf (stderr, "compare_collect mode = %s, operands::",
372 GET_MODE_NAME (mode));
373 debug_rtx (op0);
374 debug_rtx (op1);
375 }
376 branch_cmp_op[0] = op0;
377 branch_cmp_op[1] = op1;
378 branch_cmp_mode = mode;
379}
380
381/* Return the mode and operands saved with compare_collect for use
382 in a branch operator. */
383
384void
385compare_restore (operands, mode, insn)
386 rtx *operands;
387 enum machine_mode *mode;
388 rtx insn;
389{
390 if (!branch_cmp_op[0] || !branch_cmp_op[1])
391 abort_with_insn (insn, "Compare_restore did not follow compare_collect");
392
393 if (TARGET_DEBUGD_MODE)
394 {
395 fprintf (stderr,
396 "compare_restore returning mode = %s, operands:%X,%X:",
397 GET_MODE_NAME (branch_cmp_mode),
398 branch_cmp_op[0],
399 branch_cmp_op[1]);
400
401 debug_rtx (branch_cmp_op[0]);
402 debug_rtx (branch_cmp_op[1]);
403 }
404
405 operands[0] = branch_cmp_op[0];
406 operands[1] = branch_cmp_op[1];
407 *mode = branch_cmp_mode;
408
409 /* If the next insn is not a JUMP (after accounting for line numbers),
410 zero out the branch_cmp_array. Switch statements implemented as if's
411 tend to have multiple jumps. */
412 do
413 {
414 insn = NEXT_INSN (insn);
415 }
416 while (insn && GET_CODE (insn) == NOTE);
417
418 if (!insn || GET_CODE (insn) != JUMP_INSN)
419 {
420 branch_cmp_op[0] = NULL;
421 branch_cmp_op[1] = NULL;
422 branch_cmp_mode = VOIDmode;
423 }
424
425}
426\f
427/* Print the options used in the assembly file. */
428
429static struct {char *name; int value;} target_switches []
430 = TARGET_SWITCHES;
431
432void
433print_options (out)
434 FILE *out;
435{
436 int line_len;
437 int len;
438 int j;
439 char **p;
440 int mask = TARGET_DEFAULT;
441 extern char **save_argv;
442 extern char *version_string, *language_string;
443
444#if 0
445 /* Allow assembly language comparisons with -mdebug eliminating the
446 compiler version number and switch lists. */
447 if (!TARGET_DEBUG_MODE)
448 {
449 fprintf (out, "\n # %s %s", language_string, version_string);
450#ifdef TARGET_VERSION_INTERNAL
451 TARGET_VERSION_INTERNAL (out);
452#endif
453#ifdef __GNUC__
454 fprintf (out, " compiled by GNU C\n\n");
455#else
456 fprintf (out, " compiled by CC\n\n");
457#endif
458
459 fprintf (out, " # Cc1 defaults:");
460 line_len = 32767;
461 for (j = 0; j < sizeof target_switches / sizeof target_switches[0]; j++)
462 if (target_switches[j].name[0] != '\0'
463 && target_switches[j].value > 0
464 && (target_switches[j].value & mask) == target_switches[j].value)
465 {
466 len = strlen (target_switches[j].name) + 1;
467 if (len + line_len > 79)
468 {
469 line_len = 2;
470 fputs ("\n #", out);
471 }
472 fprintf (out, " -m%s", target_switches[j].name);
473 line_len += len;
474 }
475
476 fprintf (out, "\n\n # Cc1 arguments (-G value = %d):",
477 mips_section_threshold);
478
479 line_len = 32767;
480 for (p = &save_argv[1]; *p != (char *)0; p++)
481 if (**p == '-')
482 {
483 len = strlen (*p) + 1;
484 if (len + line_len > 79)
485 {
486 line_len = 2;
487 fputs ("\n #", out);
488 }
489 fprintf (out, " %s", *p);
490 line_len += len;
491 }
492 fputs ("\n\n", out);
493 }
494
495#endif
496}
497
498\f
499
500/* Abort after printing out a specific insn. */
501
502void
503abort_with_insn (insn, reason)
504 rtx insn;
505 char *reason;
506{
507 error (reason);
508 debug_rtx (insn);
509 abort ();
510}
511
512/* Write a message to stderr (for use in macros expanded in files that do not
513 include stdio.h). */
514
515void
516trace (s, s1, s2)
517 char *s, *s1, *s2;
518{
519 fprintf (stderr, s, s1, s2);
520}
521
522\f
523/* Set up the threshold for data to go into the small data area, instead
524 of the normal data area, and detect any conflicts in the switches. */
525
526void
527overide_options ()
528{
529 register int i;
530
531 i = TARGET_GVALUE;
532 if (i >= 6)
533 i += 3;
534 mips_section_threshold = (i != 0) ? 1 << i : 0;
535}
536\f
537/* If optimizing for the global pointer, keep track of all of
538 the externs, so that at the end of the file, we can emit
539 the appropriate .extern declaration for them, before writing
540 out the text section. We assume that all names passed to
541 us are in the permanent obstack, so that they will be valid
542 at the end of the compilation.
543
544 If we have -G 0, or the extern size is unknown, don't bother
545 emitting the .externs. */
546
547int
548mips_output_external (file, decl, name)
549 FILE *file;
550 tree decl;
551 char *name;
552{
553 extern char *permalloc ();
554 register struct extern_list *p;
555 int len;
556
557 if (TARGET_GP_OPT
558 && mips_section_threshold != 0
559 && ((TREE_CODE (decl)) != FUNCTION_DECL)
560 && ((len = int_size_in_bytes (TREE_TYPE (decl))) > 0))
561 {
562 p = (struct extern_list *)permalloc ((long) sizeof (struct extern_list));
563 p->next = extern_head;
564 p->name = name;
565 p->size = len;
566 extern_head = p;
567 }
568 return 0;
569}
570\f
571/* If we are optimizing the global pointer, emit the text section now
572 and any small externs which did not have .comm, etc that are
573 needed. Also, give a warning if the data area is more than 32K and
574 -pic because 3 instructions are needed to reference the data
575 pointers. */
576
577int
578mips_asm_file_end (file)
579 FILE *file;
580{
581 char buffer[8192];
582 tree name_tree;
583 struct extern_list *p;
584 int len;
585 extern tree lookup_name ();
586
587 if (TARGET_GP_OPT)
588 {
589 if (extern_head)
590 fputs ("\n", file);
591
592 for (p = extern_head; p != 0; p = p->next)
593 {
594 name_tree = get_identifier (p->name);
595 if (!TREE_ADDRESSABLE (name_tree))
596 {
597 TREE_ADDRESSABLE (name_tree) = 1;
598 fprintf (file, "\t.extern\t%s, %d\n", p->name, p->size);
599 }
600 }
601
602 fprintf (file, "\n\t.text\n");
603 rewind (asm_out_text_file);
604 if (ferror (asm_out_text_file))
605 fatal_io_error ("write of text assembly file in mips_asm_file_end");
606
607 while ((len = fread (buffer, 1, sizeof (buffer), asm_out_text_file)) > 0)
608 if (fwrite (buffer, 1, len, file) != len)
609 pfatal_with_name ("write of final assembly file in mips_asm_file_end");
610
611 if (len < 0)
612 pfatal_with_name ("read of text assembly file in mips_asm_file_end");
613
614 if (fclose (asm_out_text_file) != 0)
615 pfatal_with_name ("close of tempfile in mips_asm_file_end");
616 }
617}
618\f
619/* Fix references to the frame pointer to be off of the stack pointer. */
620
621struct rtx_def *
622mips_fix_frame_pointer (oldaddr, depth)
623 rtx oldaddr;
624 int depth;
625{
626 rtx newaddr;
627 rtx sp_diff_rtx;
628 char temp[40];
629 int frame_offset = 0;
630 extern rtx eliminate_constant_term ();
631
632 newaddr = eliminate_constant_term (oldaddr, &frame_offset);
633 if (newaddr != frame_pointer_rtx)
634 return oldaddr;
635
636 if (sp_fp_difference == (char *)0)
637 {
638 sprintf (temp, "$Ls%d", number_functions_processed);
639 sp_fp_difference = IDENTIFIER_POINTER (get_identifier (temp));
640 }
641
642 sp_diff_rtx = gen_rtx (SYMBOL_REF, SImode, sp_fp_difference);
643 if (frame_offset + depth == 0)
644 newaddr = gen_rtx (PLUS, Pmode, stack_pointer_rtx, sp_diff_rtx);
645 else
646 newaddr = gen_rtx (PLUS, Pmode,
647 stack_pointer_rtx,
648 gen_rtx (CONST, Pmode,
649 gen_rtx (PLUS, Pmode,
650 sp_diff_rtx,
651 gen_rtx (CONST_INT, VOIDmode,
652 frame_offset + depth))));
653
654 if (TARGET_DEBUGC_MODE)
655 {
656 fprintf (stderr,
657 "\n==================== FIX_FRAME, depth = %d, sp prealloc = %d, offset = %d\n",
658 depth, stack_args_preallocated, frame_offset);
659
660 fprintf (stderr, "old INSN:");
661 debug_rtx (oldaddr);
662
663 fprintf (stderr, "\nnew INSN:");
664 debug_rtx (newaddr);
665 }
666
667 return newaddr;
668}
669
670\f
671/* Set up the stack and frame (if desired) for the function. */
672
673void
674function_prologue (file, size)
675 FILE *file;
676 int size;
677{
678 extern char call_used_regs[];
679 extern char *reg_numchar[];
680 extern tree current_function_decl;
681 int regno;
682 int mask;
683 int fmask;
684 int push_loc;
685 int tsize;
686 int num_regs;
687 char **reg_name_ptr = (TARGET_NAME_REGS) ? reg_names : reg_numchar;
688 char *base_str;
689 char *sp_str = reg_name_ptr[STACK_POINTER_REGNUM];
690 char *fp_str = (!frame_pointer_needed)
691 ? sp_str
692 : reg_name_ptr[FRAME_POINTER_REGNUM];
693 tree fndecl = current_function_decl; /* current... is tooo long */
694 tree fntype = TREE_TYPE (fndecl);
695 tree fnargs = (TREE_CODE (fntype) != METHOD_TYPE)
696 ? DECL_ARGUMENTS (fndecl)
697 : 0;
698 tree next_arg;
699 tree cur_arg;
700 char *arg_name = (char *)0;
701 CUMULATIVE_ARGS args_so_far;
702
703
704 inside_function = 1;
705
706
707 if (write_symbols != NO_DEBUG)
708 ASM_OUTPUT_SOURCE_LINE (file,
709 DECL_SOURCE_LINE (current_function_decl));
710
711 fprintf (file, "\t.ent\t%s\n%s:\n", current_function_name,
712 current_function_name);
713
714 fprintf (file, " #PROLOGUE\n");
715
716 /* Determine the last argument, and get it's name. */
717 for (cur_arg = fnargs; cur_arg != (tree)0; cur_arg = next_arg)
718 {
719 next_arg = TREE_CHAIN (cur_arg);
720 if (next_arg == (tree)0)
721 {
722 if (DECL_NAME (cur_arg))
723 arg_name = IDENTIFIER_POINTER (DECL_NAME (cur_arg));
724
725 break;
726 }
727 }
728
729 /* If this function is a varargs function, store any registers that
730 would normally hold arguments ($4 - $7) on the stack. */
731 if ((TYPE_ARG_TYPES (fntype) != 0
732 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) != void_type_node))
733 || (arg_name
734 && (strcmp (arg_name, "__builtin_va_alist") == 0
735 || strcmp (arg_name, "va_alist") == 0)))
736 {
737 tree parm;
738
739 regno = 4;
740 INIT_CUMULATIVE_ARGS (args_so_far, fntype);
741
742 for (parm = fnargs; (parm && (regno <= 7)); parm = TREE_CHAIN (parm))
743 {
744 rtx entry_parm;
745 enum machine_mode passed_mode;
746 tree type;
747
748 type = DECL_ARG_TYPE (parm);
749 passed_mode = TYPE_MODE (type);
750 entry_parm = FUNCTION_ARG (args_so_far, passed_mode,
751 DECL_ARG_TYPE (parm), 1);
752
753 if (entry_parm)
754 {
755 int words;
756
757 /* passed in a register, so will get homed automatically */
758 if (GET_MODE (entry_parm) == BLKmode)
759 words = (int_size_in_bytes (type) + 3) / 4;
760 else
761 words = (GET_MODE_SIZE (GET_MODE (entry_parm)) + 3) / 4;
762
763 regno = REGNO (entry_parm) + words - 1;
764 }
765 else
766 {
767 regno = 8;
768 break;
769 }
770
771 FUNCTION_ARG_ADVANCE (args_so_far, passed_mode,
772 DECL_ARG_TYPE (parm), 1);
773 }
774
775 switch (regno)
776 {
777 case 4:
778 fprintf(file, "\tsd\t%s,0(%s)\t#varargs: home regs 4-5\n",
779 reg_name_ptr[4], sp_str);
780
781 fprintf(file, "\tsd\t%s,8(%s)\t#varargs: home regs 6-7\n",
782 reg_name_ptr[6], sp_str);
783 break;
784
785 case 5:
786 fprintf(file, "\tsw\t%s,4(%s)\t#varargs: home reg 5\n",
787 reg_name_ptr[5], sp_str);
788
789 fprintf(file, "\tsd\t%s,8(%s)\t#varargs: home regs 6-7\n",
790 reg_name_ptr[6], sp_str);
791 break;
792
793 case 6:
794 fprintf(file, "\tsd\t%s,8(%s)\t#varargs: home regs 6-7\n",
795 reg_name_ptr[6], sp_str);
796 break;
797
798 case 7:
799 fprintf(file, "\tsw\t%s,12(%s)\t#varargs: home reg 7\n",
800 reg_name_ptr[7], sp_str);
801 break;
802
803 default:
804 break;
805 }
806 }
807
808 mask = 0;
809 fmask = 0;
810 num_regs = 0;
811 push_loc = stack_args_preallocated;
812 tsize = AL_ADJUST_ALIGN (size) + stack_args_preallocated;
813
814 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
815 if (MUST_SAVE_REGISTER (regno))
816 {
817 tsize += 4;
818 num_regs += 4;
819 mask |= 1 << (regno - GP_REG_FIRST);
820 }
821
822 tsize = AL_ADJUST_ALIGN (tsize);
823 num_regs = AL_ADJUST_ALIGN (num_regs);
824 for (regno = FP_REG_FIRST; regno <= FP_REG_LAST; regno += 2)
825 if (regs_ever_live[regno] && !call_used_regs[regno])
826 {
827 tsize += 8;
828 num_regs += 8;
829 fmask |= 1 << (regno - FP_REG_FIRST);
830 }
831
832 if (tsize)
833 tsize -= STARTING_FRAME_OFFSET;
834
835
836 if (!frame_pointer_needed && sp_fp_difference != (char *)0)
837 fprintf (file,"%s\t= %d\t\t\t#Difference between SP & FP\n\n",
838 sp_fp_difference, tsize);
839
840 current_function_total_framesize = tsize;
841 current_function_saved_reg_size = num_regs;
842 if (tsize > 0)
843 {
844 if (tsize <= 32767)
845 fprintf (file,
846 "\tsubu\t%s,%s,%d\t# temp= %d, regs= %d, args= %d, sfo= %d\n",
847 sp_str, sp_str, tsize, size, num_regs,
848 stack_args_preallocated, STARTING_FRAME_OFFSET);
849 else
850 fprintf (file,
851 "\tli\t%s,%d\n\tsubu\t%s,%s,%s\t# temp= %d, regs= %d, args= %d, sfo= %d\n",
852 reg_name_ptr[MIPS_TEMP1_REGNUM], tsize, sp_str, sp_str,
853 reg_name_ptr[MIPS_TEMP1_REGNUM], size, num_regs,
854 stack_args_preallocated, STARTING_FRAME_OFFSET);
855 }
856
857 fprintf (file, "\t.frame\t%s,%d,%s\n", fp_str,
858 (frame_pointer_needed) ? 0 : tsize,
859 reg_name_ptr[31]);
860
861 if (push_loc > 32767 && num_regs > 0)
862 {
863 if ((tsize - (push_loc + num_regs)) <= 32767)
864 {
865 base_str = reg_name_ptr[MIPS_TEMP1_REGNUM];
866 push_loc = tsize - push_loc;
867 }
868 else
869 {
870 base_str = reg_name_ptr[MIPS_TEMP2_REGNUM];
871 fprintf (file, "\tli\t%s,%d\n", base_str, push_loc);
872 push_loc = 0;
873 }
874 }
875 else
876 base_str = sp_str;
877
878 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
879 if ((mask & (1 << (regno - GP_REG_FIRST))) != 0)
880 {
881 fprintf (file, "\tsw\t%s,%d(%s)\n", reg_name_ptr[regno], push_loc,
882 base_str);
883 push_loc += 4;
884 }
885
886 fprintf (file, "\t.mask\t0x%08x,%d\n", mask, push_loc - tsize - 4);
887
888 push_loc = AL_ADJUST_ALIGN (push_loc);
889 for (regno = FP_REG_FIRST; regno <= FP_REG_LAST; regno += 2)
890 if ((fmask & (1 << (regno - FP_REG_FIRST))) != 0)
891 {
892 fprintf (file, "\ts.d\t%s,%d(%s)\n", reg_name_ptr[regno], push_loc,
893 base_str);
894 push_loc += 8;
895 }
896
897 fprintf (file, "\t.fmask\t0x%08x,%d\n", fmask, push_loc - tsize - 4);
898
899 if (frame_pointer_needed)
900 {
901 if (tsize <= 32767)
902 fprintf (file, "\taddu\t%s,%s,%d\t# set up frame pointer\n", fp_str, sp_str, tsize);
903 else
904 fprintf (file, "\taddu\t%s,%s,%s\t# set up frame pointer\n", fp_str, sp_str,
905 reg_name_ptr[MIPS_TEMP1_REGNUM]);
906 }
907
908 fprintf (file," #END PROLOGUE\n");
909}
910
911\f
912/* Do any necessary cleanup after a function to restore stack, frame, and regs. */
913
914void
915function_epilogue (file, size)
916 FILE *file;
917 int size;
918{
919 extern FILE *asm_out_data_file, *asm_out_file;
920 extern char call_used_regs[];
921 extern char *reg_numchar[];
922 extern char *current_function_name;
923 extern int frame_pointer_needed;
924 int regno;
925 int push_loc = stack_args_preallocated;
926 int tsize = current_function_total_framesize;
927 int num_regs = current_function_saved_reg_size;
928 char **reg_name_ptr = (TARGET_NAME_REGS) ? reg_names : reg_numchar;
929 char *sp_str = reg_name_ptr[STACK_POINTER_REGNUM];
930 char *t1_str = reg_name_ptr[MIPS_TEMP1_REGNUM];
931 char *base_str;
932
933
934 fprintf (file," #EPILOGUE\n");
935
936 if (tsize > 32767)
937 fprintf (file, "\tli\t%s,%d\n", t1_str, tsize);
938
939 if (frame_pointer_needed)
940 {
941 char *fp_str = reg_name_ptr[FRAME_POINTER_REGNUM];
942 if (tsize > 32767)
943 fprintf (file,"\tsubu\t%s,%s,%s\t# sp not trusted here\n",
944 sp_str, fp_str, t1_str);
945 else
946 fprintf (file,"\tsubu\t%s,%s,%d\t# sp not trusted here\n",
947 sp_str, fp_str, tsize);
948 }
949
950 if (push_loc > 32767 && num_regs > 0)
951 {
952 if ((tsize - (push_loc + num_regs)) <= 32767)
953 {
954 base_str = t1_str;
955 push_loc = tsize - push_loc;
956 }
957 else
958 {
959 base_str = reg_name_ptr[MIPS_TEMP2_REGNUM];
960 fprintf (file, "\tli\t%s,%d\n", base_str, push_loc);
961 push_loc = 0;
962 }
963 }
964 else
965 base_str = sp_str;
966
967 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
968 if (MUST_SAVE_REGISTER (regno))
969 {
970 fprintf (file,"\tlw\t%s,%d(%s)\n", reg_name_ptr[regno], push_loc,
971 base_str);
972 push_loc += 4;
973 }
974
975 push_loc = AL_ADJUST_ALIGN (push_loc);
976 for (regno = FP_REG_FIRST; regno <= FP_REG_LAST; regno += 2)
977 if (regs_ever_live[regno] && !call_used_regs[regno])
978 {
979 fprintf (file, "\tl.d\t%s,%d(%s)\n", reg_name_ptr[regno], push_loc,
980 base_str);
981 push_loc += 8;
982 }
983
984 if (tsize > 32767)
985 fprintf (file, "\taddu\t%s,%s,%s\n", sp_str, sp_str, t1_str);
986
987 else if (tsize > 0)
988 fprintf (file, "\taddu\t%s,%s,%d\n", sp_str, sp_str, tsize);
989
990 fprintf (file,"\tj\t%s\n", reg_name_ptr[31]);
991 fprintf (file," #END EPILOGUE\n");
992 fprintf (file,"\t.end\t%s\n", current_function_name);
993
994 /* Reset state info for each function. */
995 stack_args_pushed = 0;
996 stack_args_preallocated = 0;
997 inside_function = 0;
998 sp_fp_difference = (char *)0;
999 number_functions_processed++;
1000
1001 /* Restore the output file if optimizing the GP (optimizing the GP causes
1002 the text to be diverted to a tempfile, so that data decls come before
1003 references to the data). */
1004
1005 if (TARGET_GP_OPT)
1006 asm_out_file = asm_out_data_file;
1007}