Annotation of gcc/config/out-mips.c, revision 1.1.1.4

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.