|
|
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.3 ! root 24: #include "tree.h"
! 25: #include "flags.h"
! 26:
! 27: extern void debug_rtx ();
1.1 root 28: extern void abort_with_insn ();
29:
1.1.1.3 ! root 30: extern FILE *asm_out_file;
! 31: extern tree current_function_decl;
1.1 root 32:
33: /* Global variables for machine-dependent things. */
34:
35: char *reg_numchar[] = REGISTER_NUMCHAR;
36:
1.1.1.3 ! root 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). */
! 41: int mips_section_threshold = -1;
! 42:
! 43: /* Count the number of .file directives, so that .loc is up to date. */
! 44: int num_source_filenames = 0;
! 45:
! 46: /* Count the number of words that are pushed to pass arguments. */
! 47: int stack_args_pushed = 0;
! 48:
! 49: /* # bytes for args preallocated by function_prolog. */
! 50: int 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. */
! 54: int number_functions_processed = 0;
! 55:
! 56: /* Count the number of sdb related labels are generated (to find block
! 57: start and end boundaries). */
! 58: int sdb_label_count = 0;
! 59:
! 60: /* Next label # for each statment for Silicon Graphics IRIS systems. */
! 61: int 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. */
! 65: int 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. */
! 70: char *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. */
! 75: FILE *asm_out_data_file;
! 76: FILE *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:
! 82: struct 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. */
! 89: char *current_function_name;
! 90:
! 91: /* Size of the frame allocated for this function. */
! 92: int current_function_total_framesize;
! 93:
! 94: /* Number of bytes used to hold saved registers. */
! 95: int current_function_saved_reg_size;
! 96:
! 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:
! 100: int
! 101: uns_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: }
1.1 root 108:
109: /* Return truth value of whether OP can be used as an operands
110: where a 16 bit integer is needed */
111:
112: int
113: arith_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:
124: int
125: arith32_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:
134: int
135: small_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:
1.1.1.3 ! root 143: /* Argument support functions. */
! 144:
! 145: /* Initialize CUMULATIVE_ARGS for a function. */
! 146:
! 147: void
! 148: init_cumulative_args (cum, fntype)
! 149: CUMULATIVE_ARGS cum; /* argument info to initialize */
! 150: tree fntype; /* tree ptr for function decl */
1.1 root 151: {
1.1.1.3 ! root 152: tree param, next_param;
1.1 root 153:
1.1.1.3 ! root 154: if (TARGET_DEBUGE_MODE)
1.1 root 155: {
1.1.1.3 ! root 156: fprintf (stderr, "\ninit_cumulative_args\n");
! 157: if (fntype != (tree)0)
1.1 root 158: {
1.1.1.3 ! root 159: putc ('\n', stderr);
! 160: debug_tree (fntype);
! 161: putc ('\n', stderr);
1.1 root 162: }
163: }
1.1.1.3 ! root 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)
1.1 root 178: {
1.1.1.3 ! root 179: next_param = TREE_CHAIN (param);
! 180: if (next_param == (tree)0 && TREE_VALUE (param) != void_type_node)
! 181: cum->gp_reg_found = 1;
1.1 root 182: }
1.1.1.3 ! root 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)
1.1 root 190: {
1.1.1.3 ! root 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: }
1.1 root 200: }
201: }
202:
1.1.1.3 ! root 203: /* Advance the argument to the next argument position. */
1.1 root 204:
1.1.1.3 ! root 205: void
! 206: function_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;
1.1 root 251: }
252: }
253:
1.1.1.3 ! root 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. */
1.1 root 256:
1.1.1.3 ! root 257: struct rtx_def *
! 258: function_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;
1.1 root 266:
1.1.1.3 ! root 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);
1.1 root 272:
1.1.1.3 ! root 273: switch (mode)
! 274: {
! 275: default:
! 276: error ("Illegal mode given to function_arg");
! 277: break;
1.1 root 278:
1.1.1.3 ! root 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: }
1.1 root 287:
1.1.1.3 ! root 288: break;
1.1 root 289:
1.1.1.3 ! root 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;
1.1 root 294:
1.1.1.3 ! root 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: }
1.1 root 304:
1.1.1.3 ! root 305: if (cum->arg_words >= MAX_ARGS_IN_REGISTERS)
! 306: {
! 307: if (TARGET_DEBUGE_MODE)
! 308: fprintf (stderr, "<stack>\n");
1.1 root 309:
1.1.1.3 ! root 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 ]);
1.1 root 318:
1.1.1.3 ! root 319: return gen_rtx (REG, mode, regbase + cum->arg_words + bias);
1.1 root 320: }
321:
1.1.1.3 ! root 322:
! 323: int
! 324: function_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 */
1.1 root 329: {
1.1.1.3 ! root 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);
1.1 root 340:
1.1.1.3 ! root 341: return MAX_ARGS_IN_REGISTERS - cum->arg_words;
! 342: }
! 343:
! 344: else if (mode == DImode && cum->arg_number == MAX_ARGS_IN_REGISTERS-1)
1.1.1.2 root 345: {
1.1.1.3 ! root 346: if (TARGET_DEBUGE_MODE)
! 347: fprintf (stderr, "function_arg_partial_nregs = 1\n");
! 348:
! 349: return 1;
1.1.1.2 root 350: }
1.1 root 351:
1.1.1.3 ! root 352: return 0;
! 353: }
1.1 root 354:
355:
1.1.1.3 ! root 356: /* Routines to merge the compare and branch operators into a single entity. */
! 357:
1.1 root 358: static rtx branch_cmp_op[2];
359: static enum machine_mode branch_cmp_mode;
360:
1.1.1.3 ! root 361: /* Save the mode and operands on the current compare operator. */
! 362:
! 363: void
1.1 root 364: compare_collect (mode, op0, op1)
365: enum machine_mode mode;
366: rtx op0;
367: rtx op1;
368: {
369: if (TARGET_DEBUGD_MODE)
370: {
1.1.1.3 ! root 371: fprintf (stderr, "compare_collect mode = %s, operands::",
! 372: GET_MODE_NAME (mode));
! 373: debug_rtx (op0);
! 374: debug_rtx (op1);
1.1 root 375: }
376: branch_cmp_op[0] = op0;
377: branch_cmp_op[1] = op1;
378: branch_cmp_mode = mode;
379: }
380:
1.1.1.3 ! root 381: /* Return the mode and operands saved with compare_collect for use
! 382: in a branch operator. */
1.1 root 383:
1.1.1.3 ! root 384: void
1.1 root 385: compare_restore (operands, mode, insn)
386: rtx *operands;
387: enum machine_mode *mode;
388: rtx insn;
389: {
1.1.1.3 ! root 390: if (!branch_cmp_op[0] || !branch_cmp_op[1])
! 391: abort_with_insn (insn, "Compare_restore did not follow compare_collect");
1.1 root 392:
1.1.1.3 ! root 393: if (TARGET_DEBUGD_MODE)
1.1 root 394: {
1.1.1.3 ! root 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]);
1.1 root 400:
1.1.1.3 ! root 401: debug_rtx (branch_cmp_op[0]);
! 402: debug_rtx (branch_cmp_op[1]);
1.1 root 403: }
404:
1.1.1.3 ! root 405: operands[0] = branch_cmp_op[0];
! 406: operands[1] = branch_cmp_op[1];
1.1 root 407: *mode = branch_cmp_mode;
408:
1.1.1.3 ! root 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: }
1.1 root 424:
425: }
426:
1.1.1.3 ! root 427: /* Print the options used in the assembly file. */
! 428:
! 429: static struct {char *name; int value;} target_switches []
! 430: = TARGET_SWITCHES;
1.1 root 431:
432: void
433: print_options (out)
434: FILE *out;
435: {
1.1.1.3 ! root 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;
1.1 root 443:
1.1.1.3 ! root 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);
1.1 root 452: #endif
1.1.1.3 ! root 453: #ifdef __GNUC__
! 454: fprintf (out, " compiled by GNU C\n\n");
1.1 root 455: #else
1.1.1.3 ! root 456: fprintf (out, " compiled by CC\n\n");
1.1 root 457: #endif
458:
1.1.1.3 ! root 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: }
1.1 root 475:
1.1.1.3 ! root 476: fprintf (out, "\n\n # Cc1 arguments (-G value = %d):",
! 477: mips_section_threshold);
1.1 root 478:
1.1.1.3 ! root 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: }
1.1 root 494:
1.1.1.3 ! root 495: #endif
1.1 root 496: }
497:
1.1.1.3 ! root 498:
1.1 root 499:
1.1.1.3 ! root 500: /* Abort after printing out a specific insn. */
1.1 root 501:
502: void
503: abort_with_insn (insn, reason)
504: rtx insn;
505: char *reason;
506: {
1.1.1.3 ! root 507: error (reason);
! 508: debug_rtx (insn);
1.1 root 509: abort ();
510: }
511:
1.1.1.3 ! root 512: /* Write a message to stderr (for use in macros expanded in files that do not
! 513: include stdio.h). */
1.1 root 514:
515: void
1.1.1.3 ! root 516: trace (s, s1, s2)
! 517: char *s, *s1, *s2;
1.1 root 518: {
1.1.1.3 ! root 519: fprintf (stderr, s, s1, s2);
1.1 root 520: }
521:
1.1.1.3 ! root 522:
! 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. */
1.1 root 525:
1.1.1.3 ! root 526: void
! 527: overide_options ()
1.1 root 528: {
529: register int i;
530:
1.1.1.3 ! root 531: i = TARGET_GVALUE;
! 532: if (i >= 6)
! 533: i += 3;
! 534: mips_section_threshold = (i != 0) ? 1 << i : 0;
1.1 root 535: }
1.1.1.3 ! root 536:
! 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. */
1.1 root 546:
547: int
1.1.1.3 ! root 548: mips_output_external (file, decl, name)
1.1 root 549: FILE *file;
1.1.1.3 ! root 550: tree decl;
1.1 root 551: char *name;
552: {
1.1.1.3 ! root 553: extern char *permalloc ();
! 554: register struct extern_list *p;
! 555: int len;
! 556:
1.1 root 557: if (TARGET_GP_OPT
1.1.1.3 ! root 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;
1.1 root 567: }
568: return 0;
569: }
1.1.1.3 ! root 570:
! 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. */
1.1 root 576:
577: int
578: mips_asm_file_end (file)
579: FILE *file;
580: {
1.1.1.3 ! root 581: char buffer[8192];
! 582: tree name_tree;
! 583: struct extern_list *p;
! 584: int len;
! 585: extern tree lookup_name ();
! 586:
1.1 root 587: if (TARGET_GP_OPT)
588: {
1.1.1.3 ! root 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:
! 619: /* Fix references to the frame pointer to be off of the stack pointer. */
! 620:
! 621: struct rtx_def *
! 622: mips_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));
1.1 root 640: }
1.1.1.3 ! root 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:
! 671: /* Set up the stack and frame (if desired) for the function. */
! 672:
! 673: void
! 674: function_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:
! 912: /* Do any necessary cleanup after a function to restore stack, frame, and regs. */
! 913:
! 914: void
! 915: function_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;
1.1 root 1007: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.