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