Annotation of gcc/integrate.c, revision 1.1.1.1

1.1       root        1: /* Procedure integration for GNU CC.
                      2:    Copyright (C) 1988 Free Software Foundation, Inc.
                      3:    Contributed by Michael Tiemann ([email protected])
                      4: 
                      5: This file is part of GNU CC.
                      6: 
                      7: GNU CC is distributed in the hope that it will be useful,
                      8: but WITHOUT ANY WARRANTY.  No author or distributor
                      9: accepts responsibility to anyone for the consequences of using it
                     10: or for whether it serves any particular purpose or works at all,
                     11: unless he says so in writing.  Refer to the GNU CC General Public
                     12: License for full details.
                     13: 
                     14: Everyone is granted permission to copy, modify and redistribute
                     15: GNU CC, but only under the conditions described in the
                     16: GNU CC General Public License.   A copy of this license is
                     17: supposed to have been given to you along with GNU CC so you
                     18: can know your rights and responsibilities.  It should be in a
                     19: file named COPYING.  Among other things, the copyright notice
                     20: and this notice must be preserved on all copies.  */
                     21: 
                     22: 
                     23: #include <ctype.h>
                     24: #include <stdio.h>
                     25: #include <strings.h>
                     26: 
                     27: #include "config.h"
                     28: #include "rtl.h"
                     29: #include "tree.h"
                     30: #include "flags.h"
                     31: #include "insn-flags.h"
                     32: #include "expr.h"
                     33: 
                     34: #include "obstack.h"
                     35: #define        obstack_chunk_alloc     xmalloc
                     36: #define        obstack_chunk_free      free
                     37: extern int xmalloc ();
                     38: extern void free ();
                     39: 
                     40: extern struct obstack permanent_obstack, maybepermanent_obstack;
                     41: extern struct obstack *rtl_obstack, *saveable_obstack, *current_obstack;
                     42: 
                     43: #define MIN(x,y) ((x < y) ? x : y)
                     44: 
                     45: extern tree pushdecl ();
                     46: 
                     47: /* This is the target of the inline function being expanded,
                     48:    or NULL if there is none.  */
                     49: static rtx inline_target;
                     50: 
                     51: /* We must take special care not to disrupt life too severely
                     52:    when performing procedure integration.  One thing that that
                     53:    involves is not creating illegitimate address which reload
                     54:    cannot fix.  Since we don't know what the frame pointer is
                     55:    not capable of (in a machine independent way), we create
                     56:    a pseudo-frame pointer which will have to do for now.  */
                     57: static rtx inline_fp_rtx;
                     58: 
                     59: /* Convert old frame-pointer offsets to new.  Parameters which only
                     60:    produce values (no addresses, and are never assigned), map directly
                     61:    to the pseudo-reg of the incoming value.  Parameters that are
                     62:    assigned to but do not have their address taken are given a fresh
                     63:    pseudo-register.  Parameters that have their address take are
                     64:    given a fresh stack-slot.  */
                     65: static rtx *parm_map;
                     66: 
                     67: /* ?? Should this be done here??  It is not right now.
                     68:    Keep track of whether a given pseudo-register is the sum
                     69:    of the frame pointer and a const_int (or zero).  */
                     70: static char *fp_addr_p;
                     71: 
                     72: /* For the local variables of the procdure being integrated that live
                     73:    on the frame, FRAME_POINTER_DELTA says how much to change their
                     74:    offsets by, so that they now live in the correct place on the
                     75:    frame of the function being compiled.  */
                     76: static int fp_delta;
                     77: 
                     78: /* Return a copy of an rtx (as needed), substituting pseudo-register,
                     79:    labels, and frame-pointer offsets as necessary.  */
                     80: static rtx copy_rtx_and_substitute ();
                     81: 
                     82: static void copy_parm_decls ();
                     83: static void copy_decl_tree ();
                     84: 
                     85: static rtx try_fold_cc0 ();
                     86: 
                     87: /* We do some simple constant folding optimization.  This optimization
                     88:    really exists primarily to save time inlining a function.  It
                     89:    also help users who ask for inline functions without -O.  */
                     90: static rtx fold_out_const_cc0 ();
                     91: 
                     92: /* Zero if the current function (whose FUNCTION_DECL is FNDECL)
                     93:    is safe and reasonable to integrate into other functions.
                     94:    Nonzero means value is a warning message with a single %s
                     95:    for the function's name.  */
                     96: 
                     97: char *
                     98: function_cannot_inline_p (fndecl)
                     99:      register tree fndecl;
                    100: {
                    101:   register rtx insn;
                    102:   tree last = tree_last (TYPE_ARG_TYPES (TREE_TYPE (fndecl)));
                    103:   int nargs = list_length (DECL_ARGUMENTS (fndecl));
                    104:   int max_insns = 4 * (4 + nargs + 16*TREE_INLINE (fndecl));
                    105:   register int ninsns = 0;
                    106:   register tree parms;
                    107: 
                    108:   /* No inlines with varargs.  `grokdeclarator' gives a warning
                    109:      message about that if `inline' is specified.  This code
                    110:      it put in to catch the volunteers.  */
                    111:   if (last && TREE_VALUE (last) != void_type_node)
                    112:     return "varargs function `%s' cannot be inline";
                    113: 
                    114:   /* If its not even close, don't even look.  */
                    115:   if (get_max_uid () > 2 * max_insns)
                    116:     return "function `%s' too large to be inline";
                    117: 
                    118:   /* Don't inline functions which have BLKmode arguments.
                    119:      Don't inline functions that take the address of
                    120:        a parameter and do not specify a function prototype.  */
                    121:   for (parms = DECL_ARGUMENTS (fndecl); parms; parms = TREE_CHAIN (parms))
                    122:     {
                    123:       if (TYPE_MODE (TREE_TYPE (parms)) == BLKmode)
                    124:        return "function `%s' with large aggregate parameter cannot be inline";
                    125:       if (last == NULL_TREE && TREE_ADDRESSABLE (parms))
                    126:        return "function `%s' without prototype uses address of parameter;\n cannot be inline";
                    127:     }
                    128: 
                    129:   if (get_max_uid () > max_insns)
                    130:     {
                    131:       for (ninsns = 0, insn = get_first_nonparm_insn (); insn && ninsns < max_insns;
                    132:           insn = NEXT_INSN (insn))
                    133:        {
                    134:          if (GET_CODE (insn) == INSN
                    135:              || GET_CODE (insn) == JUMP_INSN
                    136:              || GET_CODE (insn) == CALL_INSN)
                    137:            ninsns++;
                    138:        }
                    139: 
                    140:       if (ninsns >= max_insns)
                    141:        return "function `%s' too large to be inline";
                    142:     }
                    143: 
                    144:   return 0;
                    145: }
                    146: 
                    147: /* Variables used within save_for_inline.  */
                    148: 
                    149: /* Mapping from old pesudo-register to new pseudo-registers.
                    150:    The first element of this map is reg_map[FIRST_PSEUDO_REGISTER].
                    151:    It allocated in `save_current_insns' and `expand_function_inline',
                    152:    and deallocated on exit from each of those routines.  */
                    153: static rtx *reg_map;
                    154: 
                    155: /* Mapping from old code-labels to new code-labels.
                    156:    The first element of this map is label_map[min_labelno].
                    157:    It allocated in `save_current_insns' and `expand_function_inline',
                    158:    and deallocated on exit from each of those routines.  */
                    159: static rtx *label_map;
                    160: 
                    161: /* Map pseudo reg number into the PARM_DECL for the parm living in the reg.
                    162:    Zero for a reg that isn't a parm's home.
                    163:    Only reg numbers less than max_parm_reg are mapped here.  */
                    164: static tree *parmdecl_map;
                    165: 
                    166: /* Keep track of first pseudo-register beyond those that are parms.  */
                    167: static int max_parm_reg;
                    168: 
                    169: /* On machines that perform a function return with a single
                    170:    instruction, such as the VAX, these return insns must be
                    171:    mapped into branch statements.  */
                    172: extern rtx return_label;
                    173: 
                    174: /* Copy an rtx for save_for_inline.  */
                    175: static rtx copy_for_inline ();
                    176: 
                    177: /* Make the insns and PARM_DECLs of the current function permanent
                    178:    and record other information in DECL_SAVED_INSNS to allow inlining
                    179:    of this function in subsequent calls.  */
                    180: 
                    181: void
                    182: save_for_inline (fndecl)
                    183:      tree fndecl;
                    184: {
                    185:   extern rtx *regno_reg_rtx;   /* in emit-rtl.c.  */
                    186:   extern current_function_args_size;
                    187: 
                    188:   rtx first_insn, last_insn, insn;
                    189:   rtx head, copy;
                    190:   tree parms;
                    191:   int max_labelno, min_labelno, i, len;
                    192:   int max_reg;
                    193: 
                    194:   /* Make and emit a return-label if we have not already done so.  */
                    195: 
                    196:   if (return_label == 0)
                    197:     {
                    198:       return_label = gen_label_rtx ();
                    199:       emit_label (return_label);
                    200:     }
                    201: 
                    202:   /* Get some bounds on the labels and registers used.  */
                    203: 
                    204:   max_labelno = max_label_num ();
                    205:   min_labelno = get_first_label_num ();
                    206:   max_parm_reg = max_parm_reg_num ();
                    207:   max_reg = max_reg_num ();
                    208: 
                    209:   /* Set up PARMDECL_MAP which maps pseudo-reg number to its PARM_DECL.
                    210: 
                    211:      Set TREE_VOLATILE to 0 if the parm is in a register, otherwise 1.
                    212:      Later we set TREE_READONLY to 0 if the parm is modified inside the fn.  */
                    213: 
                    214:   parmdecl_map = (tree *) alloca (max_parm_reg * sizeof (tree));
                    215: 
                    216:   for (parms = DECL_ARGUMENTS (fndecl); parms; parms = TREE_CHAIN (parms))
                    217:     {
                    218:       rtx p = DECL_RTL (parms);
                    219: 
                    220:       if (GET_CODE (p) == REG)
                    221:        {
                    222:          parmdecl_map[REGNO (p)] = parms;
                    223:          TREE_VOLATILE (parms) = 0;
                    224:        }
                    225:       else
                    226:        TREE_VOLATILE (parms) = 1;
                    227:       TREE_READONLY (parms) = 1;
                    228:     }
                    229: 
                    230:   /* The list of DECL_SAVES_INSNS, starts off with a header which
                    231:      contains the following information:
                    232: 
                    233:      the first insn of the function (not including the insns that copy
                    234:      parameters into registers).
                    235:      the first label used by that function,
                    236:      the last label used by that function,
                    237:      and the total number of registers used.  */
                    238: 
                    239:   head = gen_inline_header_rtx (NULL, NULL, min_labelno, max_labelno,
                    240:                                max_parm_reg, max_reg,
                    241:                                current_function_args_size);
                    242: 
                    243:   /* We have now allocated all that needs to be allocated permanently
                    244:      on the rtx obstack.  Set our high-water mark, so that we
                    245:      can free the rest of this when the time comes.  */
                    246: 
                    247:   preserve_data ();
                    248: 
                    249:   /* Copy the chain insns of this function.
                    250:      Install the copied chain as the insns of this function,
                    251:      for continued compilation;
                    252:      the original chain is recorded as the DECL_SAVED_INSNS
                    253:      for inlining future calls.  */
                    254: 
                    255:   /* If there are insns that copy parms from the stack into pseudo registers,
                    256:      those insns are not copied.  `expand_inline_function' must
                    257:      emit the correct code to handle such things.  */
                    258: 
                    259:   insn = get_insns ();
                    260:   if (GET_CODE (insn) != NOTE)
                    261:     abort ();
                    262:   first_insn = rtx_alloc (NOTE);
                    263:   NOTE_SOURCE_FILE (first_insn) = NOTE_SOURCE_FILE (insn);
                    264:   NOTE_LINE_NUMBER (first_insn) = NOTE_LINE_NUMBER (insn);
                    265:   INSN_UID (first_insn) = INSN_UID (insn);
                    266:   PREV_INSN (first_insn) = NULL;
                    267:   NEXT_INSN (first_insn) = NULL;
                    268:   last_insn = first_insn;
                    269: 
                    270:   /* Each pseudo-reg in the old insn chain must have a unique rtx in the copy.
                    271:      Make these new rtx's now, and install them in regno_reg_rtx, so they
                    272:      will be the official pseudo-reg rtx's for the rest of compilation.  */
                    273: 
                    274:   reg_map = (rtx *) alloca ((max_reg + 1) * sizeof (rtx));
                    275: 
                    276:   len = sizeof (struct rtx_def) + (GET_RTX_LENGTH (REG) - 1) * sizeof (rtunion);
                    277:   for (i = max_reg - 1; i >= FIRST_PSEUDO_REGISTER; i--)
                    278:     reg_map[i] = (rtx)obstack_copy (&maybepermanent_obstack, regno_reg_rtx[i], len);
                    279:   bcopy (reg_map + FIRST_PSEUDO_REGISTER,
                    280:         regno_reg_rtx + FIRST_PSEUDO_REGISTER,
                    281:         (max_reg_num () - FIRST_PSEUDO_REGISTER) * sizeof (rtx));
                    282: 
                    283:   /* Likewise each label rtx must have a unique rtx as its copy.  */
                    284: 
                    285:   label_map = (rtx *)alloca ((max_labelno - min_labelno) * sizeof (rtx));
                    286:   label_map -= min_labelno;
                    287: 
                    288:   for (i = min_labelno; i < max_labelno; i++)
                    289:     label_map[i] = gen_label_rtx ();
                    290: 
                    291:   /* Now copy the chain of insns.  */
                    292: 
                    293:   for (insn = NEXT_INSN (insn); insn; insn = NEXT_INSN (insn))
                    294:     {
                    295:       switch (GET_CODE (insn))
                    296:        {
                    297:        case NOTE:
                    298:          copy = rtx_alloc (NOTE);
                    299:          NOTE_SOURCE_FILE (copy) = NOTE_SOURCE_FILE (insn);
                    300:          NOTE_LINE_NUMBER (copy) = NOTE_LINE_NUMBER (insn);
                    301:          break;
                    302: 
                    303:        case INSN:
                    304:        case CALL_INSN:
                    305:        case JUMP_INSN:
                    306:          copy = rtx_alloc (GET_CODE (insn));
                    307:          PATTERN (copy) = copy_for_inline (PATTERN (insn));
                    308:          INSN_CODE (copy) = -1;
                    309:          LOG_LINKS (copy) = NULL;
                    310:          REG_NOTES (copy) = copy_for_inline (REG_NOTES (insn));
                    311:          break;
                    312: 
                    313:        case CODE_LABEL:
                    314:          copy = label_map[CODE_LABEL_NUMBER (insn)];
                    315:          break;
                    316: 
                    317:        case BARRIER:
                    318:          copy = rtx_alloc (BARRIER);
                    319:          break;
                    320: 
                    321:        default:
                    322:          abort ();
                    323:        }
                    324:       INSN_UID (copy) = INSN_UID (insn);
                    325:       NEXT_INSN (last_insn) = copy;
                    326:       PREV_INSN (copy) = last_insn;
                    327:       last_insn = copy;
                    328:     }
                    329: 
                    330:   NEXT_INSN (last_insn) = NULL;
                    331: 
                    332:   NEXT_INSN (head) = get_first_nonparm_insn ();
                    333:   FIRST_PARM_INSN (head) = get_insns ();
                    334:   DECL_SAVED_INSNS (fndecl) = head;
                    335:   DECL_FRAME_SIZE (fndecl) = get_frame_size ();
                    336:   TREE_INLINE (fndecl) = 1;
                    337: 
                    338:   parmdecl_map = 0;
                    339:   label_map = 0;
                    340:   reg_map = 0;
                    341:   return_label = 0;
                    342: 
                    343:   set_new_first_and_last_insn (first_insn, last_insn);
                    344: }
                    345: 
                    346: /* Copy the rtx ORIG recursively, replacing pseudo-regs and labels
                    347:    according to `reg_map' and `label_map'.
                    348:    All other kinds of rtx are copied except those that can never be
                    349:    changed during compilation.  */
                    350: 
                    351: static rtx
                    352: copy_for_inline (orig)
                    353:      rtx orig;
                    354: {
                    355:   register rtx x = orig;
                    356:   register int i;
                    357:   register enum rtx_code code;
                    358:   register char *format_ptr;
                    359: 
                    360:   if (x == 0)
                    361:     return x;
                    362: 
                    363:   code = GET_CODE (x);
                    364: 
                    365:   /* These types may be freely shared.  */
                    366: 
                    367:   switch (code)
                    368:     {
                    369:     case QUEUED:
                    370:     case CONST_INT:
                    371:     case CONST_DOUBLE:
                    372:     case SYMBOL_REF:
                    373:     case CODE_LABEL:
                    374:     case PC:
                    375:     case CC0:
                    376:       return x;
                    377: 
                    378:     case MEM:
                    379:       /* A MEM is allowed to be shared if its address is constant
                    380:         or is a constant plus one of the special registers.  */
                    381:       if (CONSTANT_ADDRESS_P (XEXP (x, 0)))
                    382:        return x;
                    383:       if (GET_CODE (XEXP (x, 0)) == PLUS
                    384:          && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
                    385:          && (REGNO (XEXP (XEXP (x, 0), 0)) == FRAME_POINTER_REGNUM
                    386:              || REGNO (XEXP (XEXP (x, 0), 0)) == ARG_POINTER_REGNUM)
                    387:          && CONSTANT_ADDRESS_P (XEXP (XEXP (x, 0), 1)))
                    388:        if (GET_CODE (XEXP (x, 0)) == REG
                    389:            && (REGNO (XEXP (x, 0)) == FRAME_POINTER_REGNUM
                    390:                || REGNO (XEXP (x, 0)) == ARG_POINTER_REGNUM)
                    391:            && CONSTANT_ADDRESS_P (XEXP (x, 1)))
                    392:        return x;
                    393:       break;
                    394: 
                    395:     case LABEL_REF:
                    396:       {
                    397:        /* Must point to the new insn.  */
                    398:        return gen_rtx (LABEL_REF, GET_MODE (orig),
                    399:                        label_map[CODE_LABEL_NUMBER (XEXP (orig, 0))]);
                    400:       }
                    401: 
                    402:     case REG:
                    403:       if (REGNO (x) >= FIRST_PSEUDO_REGISTER)
                    404:        return reg_map [REGNO (x)];
                    405:       else
                    406:        return x;
                    407: 
                    408:       /* If a parm that gets modified lives in a pseudo-reg,
                    409:         set its TREE_VOLATILE to prevent certain optimizations.  */
                    410:     case SET:
                    411:       {
                    412:        rtx dest = SET_DEST (x);
                    413: 
                    414:        if (GET_CODE (dest) == REG
                    415:            && REGNO (dest) < max_parm_reg
                    416:            && REGNO (dest) >= FIRST_PSEUDO_REGISTER)
                    417:          TREE_READONLY (parmdecl_map[REGNO (dest)]) = 0;
                    418:       }
                    419:       break;
                    420:     }
                    421: 
                    422:   /* Replace this rtx with a copy of itself.  */
                    423: 
                    424:   x = rtx_alloc (code);
                    425:   bcopy (orig, x, sizeof (int) * (GET_RTX_LENGTH (code) + 1));
                    426: 
                    427:   /* Now scan the subexpressions recursively.
                    428:      We can store any replaced subexpressions directly into X
                    429:      since we know X is not shared!  Any vectors in X
                    430:      must be copied if X was copied.  */
                    431: 
                    432:   format_ptr = GET_RTX_FORMAT (code);
                    433: 
                    434:   for (i = 0; i < GET_RTX_LENGTH (code); i++)
                    435:     {
                    436:       switch (*format_ptr++)
                    437:        {
                    438:        case 'e':
                    439:          XEXP (x, i) = copy_for_inline (XEXP (x, i));
                    440:          break;
                    441: 
                    442:        case 'E':
                    443:          if (XVEC (x, i) != NULL)
                    444:            {
                    445:              register int j;
                    446: 
                    447:              XVEC (x, i) = gen_rtvec_v (XVECLEN (x, i), &XVECEXP (x, i, 0));
                    448:              for (j = 0; j < XVECLEN (x, i); j++)
                    449:                XVECEXP (x, i, j)
                    450:                  = copy_for_inline (XVECEXP (x, i, j));
                    451:            }
                    452:          break;
                    453:        }
                    454:     }
                    455:   return x;
                    456: }
                    457: 
                    458: /* Integrate the procedure defined by FNDECL.  Note that this function
                    459:    may wind up calling itself.  Since the static variables are not
                    460:    reentrant, we do not assign them until after the possibility
                    461:    or recursion is eliminated.
                    462: 
                    463:    If IGNORE is nonzero, do not produce a value.
                    464:    Otherwise store the value in TARGET if it is nonzero and that is convenient.
                    465: 
                    466:    Value is:
                    467:    (rtx)-1 if we could not substitute the function
                    468:    0 if we substituted it and it does not produce a value
                    469:    else an rtx for where the value is stored.  */
                    470: 
                    471: rtx
                    472: expand_inline_function (fndecl, parms, target, ignore, type, structure_value_addr)
                    473:      tree fndecl, parms;
                    474:      rtx target;
                    475:      int ignore;
                    476:      tree type;
                    477:      rtx structure_value_addr;
                    478: {
                    479:   tree formal, actual;
                    480:   rtx header = DECL_SAVED_INSNS (fndecl);
                    481:   rtx insns = FIRST_FUNCTION_INSN (header);
                    482:   rtx insn, protect;
                    483:   rtx last_insn = get_last_insn ();
                    484:   int max_regno = MAX_REGNUM (header) + 1;
                    485:   register int i;
                    486:   int keep;
                    487:   int min_labelno = FIRST_LABELNO (header);
                    488:   int max_labelno = LAST_LABELNO (header);
                    489:   int nargs;
                    490:   rtx *arg_vec;
                    491:   rtx return_label = 0;
                    492:   rtx follows_call = 0;
                    493: 
                    494:   if (max_regno < FIRST_PSEUDO_REGISTER)
                    495:     return (rtx)-1;
                    496: 
                    497:   nargs = list_length (DECL_ARGUMENTS (fndecl));
                    498: 
                    499:   /* We expect PARMS to have the right length; don't crash if not.  */
                    500:   if (list_length (parms) != nargs)
                    501:     return (rtx)-1;
                    502: 
                    503:   /* Make a fresh binding contour that we can easily remove.  */
                    504:   pushlevel (0);
                    505:   expand_start_bindings (0);
                    506: 
                    507:   /* Get all the actual args as RTL, and store them in ARG_VEC.  */
                    508: 
                    509:   arg_vec = (rtx *)alloca (nargs * sizeof (rtx));
                    510: 
                    511:   for (formal = DECL_ARGUMENTS (fndecl),
                    512:        actual = parms,
                    513:        i = 0;
                    514:        formal;
                    515:        formal = TREE_CHAIN (formal),
                    516:        actual = TREE_CHAIN (actual),
                    517:        i++)
                    518:     {
                    519:       tree arg = TREE_VALUE (actual); /* this has already been converted */
                    520:       enum machine_mode tmode = TYPE_MODE (TREE_TYPE (formal));
                    521:       tree decl = formal;
                    522:       rtx copy;
                    523: 
                    524:       emit_note (DECL_SOURCE_FILE (decl), DECL_SOURCE_LINE (decl));
                    525: 
                    526:       if (TREE_ADDRESSABLE (formal))
                    527:        {
                    528:          int size = int_size_in_bytes (TREE_TYPE (formal));
                    529:          copy = assign_stack_local (tmode, size);
                    530:          store_expr (arg, copy, 0);
                    531:        }
                    532:       else if (! TREE_READONLY (formal)
                    533:               || TREE_VOLATILE (formal))
                    534:        {
                    535:          /* If parm is modified or if it hasn't a pseudo reg,
                    536:             we may not simply substitute the actual value;
                    537:             copy it through a register.  */
                    538:          copy = gen_reg_rtx (tmode);
                    539:          store_expr (arg, copy, 0);
                    540:        }
                    541:       else
                    542:        {
                    543:          copy = expand_expr (arg, 0, tmode, 0);
                    544: 
                    545:          /* We do not use CONSTANT_ADDRESS_P here because
                    546:             the set of cases where that might make a difference
                    547:             are a subset of the cases that arise even when
                    548:             it is a CONSTANT_ADDRESS_P (i.e., fp_delta
                    549:             gets into the act.  */
                    550:          if (GET_CODE (copy) != REG && ! CONSTANT_P (copy))
                    551:            copy = copy_to_reg (copy);
                    552:        }
                    553:       arg_vec[i] = copy;
                    554:     }
                    555: 
                    556:   copy_parm_decls (DECL_ARGUMENTS (fndecl), arg_vec);
                    557: 
                    558:   /* Perform postincrements before actually calling the function.  */
                    559:   emit_queue ();
                    560: 
                    561:   /* clean up stack so that variables might have smaller offsets.  */
                    562:   do_pending_stack_adjust ();
                    563: 
                    564:   /* Pass the function the address in which to return a structure value.  */
                    565:   if (structure_value_addr)
                    566:     emit_move_insn (struct_value_rtx, structure_value_addr);
                    567: 
                    568:   /* Now prepare for copying the insns.
                    569:      Set up reg_map, parm_map and label_map saying how to translate
                    570:      the pseudo-registers, stack-parm references and labels when copying.  */
                    571: 
                    572:   reg_map = (rtx *) alloca (max_regno * sizeof (rtx));
                    573:   bzero (reg_map, max_regno * sizeof (rtx));
                    574: 
                    575:   if (DECL_ARGUMENTS (fndecl))
                    576:     {
                    577:       tree decl = DECL_ARGUMENTS (fndecl);
                    578:       tree last = tree_last (decl);
                    579:       int offset = FUNCTION_ARGS_SIZE (header);
                    580:       parm_map =
                    581:        (rtx *)alloca ((offset / UNITS_PER_WORD) * sizeof (rtx));
                    582:       bzero (parm_map, (offset / UNITS_PER_WORD) * sizeof (rtx));
                    583:       parm_map -= FIRST_PARM_OFFSET / UNITS_PER_WORD;
                    584: 
                    585:       for (formal = decl, i = 0; formal; formal = TREE_CHAIN (formal), i++)
                    586:        {
                    587:          /* Create an entry in PARM_MAP that says what pseudo register
                    588:             is associated with an address we might compute.  */
                    589:          parm_map[DECL_OFFSET (formal) / BITS_PER_WORD] = arg_vec[i];
                    590:          /* Create an entry in REG_MAP that says what rtx is associated
                    591:             with a pseudo register from the function being inlined.  */
                    592:          if (GET_CODE (DECL_RTL (formal)) == REG)
                    593:            reg_map[REGNO (DECL_RTL (formal))] = arg_vec[i];
                    594:        }
                    595:     }
                    596:   else
                    597:     {
                    598:       parm_map = NULL;
                    599:     }
                    600: 
                    601:   label_map = (rtx *)alloca ((max_labelno - min_labelno) * sizeof (rtx));
                    602:   label_map -= min_labelno;
                    603: 
                    604:   for (i = min_labelno; i < max_labelno; i++)
                    605:     label_map[i] = gen_label_rtx ();
                    606: 
                    607:   /* Set up a target to translate the inline function's value-register.  */
                    608: 
                    609:   if (structure_value_addr != 0 || TYPE_MODE (type) == VOIDmode)
                    610:     inline_target = 0;
                    611:   else if (target && GET_MODE (target) == TYPE_MODE (type))
                    612:     inline_target = target;
                    613:   else
                    614:     inline_target = gen_reg_rtx (TYPE_MODE (type));
                    615: 
                    616:   /* We are about to make space in this function's stack frame
                    617:      for a copy of the stack frame of the inline function.
                    618:      First, create an RTX that points to that stack frame
                    619:      with the same offset usually used for the frame pointer.
                    620:      This will be substituted for all frame-pointer references.  */
                    621: 
                    622:   fp_delta = get_frame_size ();
                    623: #ifdef FRAME_GROWS_DOWNWARD
                    624:   fp_delta = - fp_delta;
                    625: #endif
                    626:   fp_delta -= STARTING_FRAME_OFFSET;
                    627: 
                    628:   inline_fp_rtx
                    629:     = copy_to_mode_reg (Pmode,
                    630:                        plus_constant (frame_pointer_rtx, fp_delta));
                    631: 
                    632:   /* Now allocate the space for that to point at.  */
                    633: 
                    634:   assign_stack_local (VOIDmode, DECL_FRAME_SIZE (fndecl));
                    635: 
                    636:   /* Now copy the insns one by one.  */
                    637: 
                    638:   for (insn = insns; insn; insn = NEXT_INSN (insn))
                    639:     {
                    640:       rtx copy, pattern, next = 0;
                    641: 
                    642:       switch (GET_CODE (insn))
                    643:        {
                    644:        case INSN:
                    645:          pattern = PATTERN (insn);
                    646: 
                    647:          /* Special handling for the insn immediately after a CALL_INSN
                    648:             that returned a value:
                    649:             If it does copy the value, we must avoid the usual translation
                    650:             of the return-register into INLINE_TARGET.
                    651:             If it just USEs the value, the inline function expects it to
                    652:             stay in the return-register and be returned,
                    653:             so copy it into INLINE_TARGET.  */
                    654: 
                    655:          if (follows_call
                    656:              /* Allow a stack-adjust, handled normally, to come in between
                    657:                 the call and the value-copying insn.  */
                    658:              && ! (GET_CODE (pattern) == SET
                    659:                    && SET_DEST (pattern) == stack_pointer_rtx))
                    660:            {
                    661:              if (GET_CODE (pattern) == SET
                    662:                  && rtx_equal_p (SET_SRC (pattern), follows_call))
                    663:                /* This insn copies the value: take special care to copy
                    664:                   that value to this insn's destination.  */
                    665:                {
                    666:                  copy = emit_insn (gen_rtx (SET, VOIDmode,
                    667:                                             copy_rtx_and_substitute (SET_DEST (pattern)),
                    668:                                             follows_call));
                    669:                  copy->integrated = 1;
                    670:                  follows_call = 0;
                    671:                  break;
                    672:                }
                    673:              else if (GET_CODE (pattern) == USE
                    674:                       && rtx_equal_p (XEXP (pattern, 0), follows_call))
                    675:                /* This insn does nothing but says the value is expected
                    676:                   to flow through to the inline function's return-value.
                    677:                   Make that happen, then ignore this insn.  */
                    678:                {
                    679:                  copy = emit_insn (gen_rtx (SET, VOIDmode, inline_target,
                    680:                                             follows_call));
                    681:                  copy->integrated = 1;
                    682:                  follows_call = 0;
                    683:                  break;
                    684:                }
                    685:              /* If it does neither, this value must be ignored.  */
                    686:              follows_call = 0;
                    687:            }
                    688: 
                    689:          /* The (USE (REG n)) at return from the function should be ignored
                    690:             since we are changing (REG n) into inline_target.  */
                    691:          if (GET_CODE (pattern) == USE
                    692:              && GET_CODE (XEXP (pattern, 0)) == REG
                    693:              && FUNCTION_VALUE_REGNO_P (REGNO (XEXP (pattern, 0))))
                    694:            break;
                    695: 
                    696:          /* Try to do some quick constant folding here.
                    697:             This will save save execution time of the compiler,
                    698:             as well time and space of the program if done here.  */
                    699:          if (GET_CODE (pattern) == SET
                    700:              && SET_DEST (pattern) == cc0_rtx)
                    701:            next = try_fold_cc0 (insn);
                    702: 
                    703:          if (next != 0)
                    704:            {
                    705:              insn = next;
                    706:            }
                    707:          else
                    708:            {
                    709:              copy = emit_insn (copy_rtx_and_substitute (pattern));
                    710:              copy->integrated = 1;
                    711:            }
                    712:          break;
                    713: 
                    714:        case JUMP_INSN:
                    715:          follows_call = 0;
                    716:          if (GET_CODE (PATTERN (insn)) == RETURN)
                    717:            {
                    718:              if (return_label == 0)
                    719:                return_label = gen_label_rtx ();
                    720:              emit_jump (return_label);
                    721:              break;
                    722:            }
                    723:          copy = emit_jump_insn (copy_rtx_and_substitute (PATTERN (insn)));
                    724:          copy->integrated = 1;
                    725:          break;
                    726: 
                    727:        case CALL_INSN:
                    728:          {
                    729:            rtx newbod;
                    730:            /* If the call's body is (set (reg...) (call...)),
                    731:               the register is a function return register, but DON'T
                    732:               translate it into INLINE_TARGET because it describes the
                    733:               called function, not the caller's return value.  */
                    734:            if (GET_CODE (PATTERN (insn)) == SET)
                    735:              newbod = gen_rtx (SET, VOIDmode, SET_DEST (PATTERN (insn)),
                    736:                                copy_rtx_and_substitute (SET_SRC (PATTERN (insn))));
                    737:            else
                    738:              newbod = copy_rtx_and_substitute (PATTERN (insn));
                    739:            copy = emit_call_insn (newbod);
                    740:          }
                    741:          copy->integrated = 1;
                    742:          /* Special handling needed for the following INSN depending on
                    743:             whether it copies the value from the fcn return reg.  */
                    744:          if (GET_CODE (PATTERN (insn)) == SET)
                    745:            follows_call = SET_DEST (PATTERN (insn));
                    746:          break;
                    747: 
                    748:        case CODE_LABEL:
                    749:          emit_label (label_map[CODE_LABEL_NUMBER (insn)]);
                    750:          follows_call = 0;
                    751:          break;
                    752: 
                    753:        case BARRIER:
                    754:          emit_barrier ();
                    755:          break;
                    756: 
                    757:        case NOTE:
                    758:          emit_note (NOTE_SOURCE_FILE (insn), NOTE_LINE_NUMBER (insn));
                    759:          break;
                    760: 
                    761:        default:
                    762:          abort ();
                    763:          break;
                    764:        }
                    765:     }
                    766: 
                    767:   if (return_label)
                    768:     emit_label (return_label);
                    769: 
                    770:   /* Make copies of the decls of the symbols in the inline function, so that
                    771:      the copies of the variables get declared in the current function.  */
                    772:   copy_decl_tree (DECL_INITIAL (fndecl), 0);
                    773: 
                    774:   /* End the scope containing the copied formal parameter variables.  */
                    775: 
                    776:   expand_end_bindings (getdecls (), 1);
                    777:   poplevel (1, 1, 0);
                    778: 
                    779:   reg_map = NULL;
                    780:   label_map = NULL;
                    781: 
                    782:   if (ignore || TYPE_MODE (type) == VOIDmode)
                    783:     return 0;
                    784: 
                    785:   if (structure_value_addr)
                    786:     {
                    787:       if (target)
                    788:        return target;
                    789:       return gen_rtx (MEM, BLKmode,
                    790:                      memory_address (BLKmode, structure_value_addr));
                    791:     }
                    792: 
                    793:   return inline_target;
                    794: }
                    795: 
                    796: /* Given a chain of PARM_DECLs, ARGS, and a vector of RTL homes VEC,
                    797:    copy each decl into a VAR_DECL, push all of those decls
                    798:    and give each one the corresponding home.  */
                    799: 
                    800: static void
                    801: copy_parm_decls (args, vec)
                    802:      tree args;
                    803:      rtx *vec;
                    804: {
                    805:   register tree tail;
                    806:   register int i;
                    807: 
                    808:   for (tail = args, i = 0; tail; tail = TREE_CHAIN (tail), i++)
                    809:     {
                    810:       register tree decl = pushdecl (build_decl (VAR_DECL, DECL_NAME (tail),
                    811:                                                 TREE_TYPE (tail)));
                    812:       DECL_RTL (decl) = vec[i];
                    813:     }
                    814: }
                    815: 
                    816: /* Given a LET_STMT node, push decls and levels
                    817:    so as to construct in the current function a tree of contexts
                    818:    isomorphic to the one that is given.  */
                    819: 
                    820: static void
                    821: copy_decl_tree (let, level)
                    822:      tree let;
                    823:      int level;
                    824: {
                    825:   tree t;
                    826: 
                    827:   pushlevel (0);
                    828:   
                    829:   for (t = STMT_VARS (let); t; t = TREE_CHAIN (t))
                    830:     {
                    831:       tree d = build_decl (TREE_CODE (t), DECL_NAME (t), TREE_TYPE (t));
                    832:       DECL_SOURCE_LINE (d) = DECL_SOURCE_LINE (t);
                    833:       DECL_SOURCE_FILE (d) = DECL_SOURCE_FILE (t);
                    834:       if (DECL_RTL (t) != 0)
                    835:        DECL_RTL (d) = copy_rtx_and_substitute (DECL_RTL (t));
                    836:       TREE_EXTERNAL (d) = TREE_EXTERNAL (t);
                    837:       TREE_STATIC (d) = TREE_STATIC (t);
                    838:       TREE_PUBLIC (d) = TREE_PUBLIC (t);
                    839:       TREE_LITERAL (d) = TREE_LITERAL (t);
                    840:       TREE_ADDRESSABLE (d) = TREE_ADDRESSABLE (t);
                    841:       TREE_READONLY (d) = TREE_READONLY (t);
                    842:       TREE_VOLATILE (d) = TREE_VOLATILE (t);
                    843:       pushdecl (d);
                    844:     }
                    845: 
                    846:   for (t = STMT_BODY (let); t; t = TREE_CHAIN (t))
                    847:     copy_decl_tree (t, level + 1);
                    848: 
                    849:   poplevel (level > 0, 0, 0);
                    850: }
                    851: 
                    852: /* Create a new copy of an rtx.
                    853:    Recursively copies the operands of the rtx,
                    854:    except for those few rtx codes that are sharable.  */
                    855: 
                    856: static rtx
                    857: copy_rtx_and_substitute (orig)
                    858:      register rtx orig;
                    859: {
                    860:   register rtx copy, temp;
                    861:   register int i, j;
                    862:   register RTX_CODE code;
                    863:   register enum machine_mode mode;
                    864:   register char *format_ptr;
                    865:   int regno;
                    866: 
                    867:   if (orig == 0)
                    868:     return 0;
                    869: 
                    870:   code = GET_CODE (orig);
                    871:   mode = GET_MODE (orig);
                    872: 
                    873:   switch (code)
                    874:     {
                    875:     case REG:
                    876:       /* If a frame-pointer register shows up, then we
                    877:         must `fix' the reference.  If the stack pointer
                    878:         register shows up, it must be part of stack-adjustments
                    879:         (*not* because we eliminated the frame pointer!).
                    880:         Small hard registers are returned as-is.  Pseudo-registers
                    881:         go through their `reg_map'.  */
                    882:       regno = REGNO (orig);
                    883:       if (regno < FIRST_PSEUDO_REGISTER)
                    884:        {
                    885:          if (FUNCTION_VALUE_REGNO_P (regno))
                    886:            return inline_target;
                    887:          if (regno == FRAME_POINTER_REGNUM)
                    888:            return plus_constant (orig, fp_delta);
                    889:          return orig;
                    890:        }
                    891:       if (reg_map[regno] == NULL)
                    892:        reg_map[regno] = gen_reg_rtx (mode);
                    893:       return reg_map[regno];
                    894: 
                    895:     case CODE_LABEL:
                    896:       return label_map[CODE_LABEL_NUMBER (orig)];
                    897: 
                    898:     case LABEL_REF:
                    899:       copy = rtx_alloc (LABEL_REF);
                    900:       PUT_MODE (copy, mode);
                    901:       XEXP (copy, 0) = label_map[CODE_LABEL_NUMBER (XEXP (orig, 0))];
                    902:       return copy;
                    903: 
                    904:     case PC:
                    905:     case CC0:
                    906:     case CONST_INT:
                    907:     case CONST_DOUBLE:
                    908:     case SYMBOL_REF:
                    909:       return orig;
                    910: 
                    911:     case PLUS:
                    912:       /* Note:  the PLUS case is not nearly as careful as the MEM
                    913:         case in terms of preserving addresses.  The reason for this
                    914:         is that it is expected that if a PLUS_EXPR turns out not
                    915:         to be a legitimate address, reload can fix that up, without
                    916:         doing major damage.  However, a MEM rtx must preside
                    917:         over a legitimate address.  The MEM case has lots of hair
                    918:         to deal with what happens when it sits on a PLUS...  */
                    919:       /* Take care of the easy case quickly.  */
                    920:       if (XEXP (orig, 0) == frame_pointer_rtx
                    921:          || XEXP (orig, 1) == frame_pointer_rtx
                    922:          || (ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
                    923:              && (XEXP (orig, 0) == arg_pointer_rtx
                    924:                  || XEXP (orig, 1) == arg_pointer_rtx)))
                    925:        {
                    926:          if (XEXP (orig, 0) == frame_pointer_rtx
                    927:              || XEXP (orig, 0) == arg_pointer_rtx)
                    928:            copy = XEXP (orig, 1);
                    929:          else
                    930:            copy = XEXP (orig, 0);
                    931: 
                    932:          if (GET_CODE (copy) == CONST_INT)
                    933:            {
                    934:              int c = INTVAL (copy);
                    935: 
                    936:              if (c > 0)
                    937:                {
                    938:                  copy = parm_map[c / UNITS_PER_WORD];
                    939:                  return XEXP (copy, 0);
                    940:                }
                    941:              return gen_rtx (PLUS, mode,
                    942:                              frame_pointer_rtx,
                    943:                              gen_rtx (CONST_INT, SImode,
                    944:                                       c + fp_delta));
                    945:            }
                    946:          copy = copy_rtx_and_substitute (copy);
                    947:          temp = gen_rtx (PLUS, mode, frame_pointer_rtx, copy);
                    948:          return plus_constant (temp, fp_delta);
                    949:        }
                    950:       else if (reg_mentioned_p (frame_pointer_rtx, orig)
                    951:               || (ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
                    952:                   && reg_mentioned_p (arg_pointer_rtx, orig)))
                    953:        {
                    954:          /* If we have a complex sum which has a frame pointer
                    955:             in it, and it was a legitimate address, then
                    956:             keep it that way.  */
                    957:          if (memory_address_p (mode, orig))
                    958:            {
                    959:              if (GET_CODE (XEXP (orig, 0)) == CONST_INT)
                    960:                {
                    961:                  copy = copy_rtx_and_substitute (XEXP (orig, 1));
                    962:                  temp = plus_constant (copy, INTVAL (XEXP (orig, 0)));
                    963:                }
                    964:              else if (GET_CODE (XEXP (orig, 1)) == CONST_INT)
                    965:                {
                    966:                  copy = copy_rtx_and_substitute (XEXP (orig, 0));
                    967:                  temp = plus_constant (copy, INTVAL (XEXP (orig, 1)));
                    968:                }
                    969:              else
                    970:                {
                    971:                  temp = gen_rtx (PLUS, GET_MODE (orig),
                    972:                                  copy_rtx_and_substitute (XEXP (orig, 0)),
                    973:                                  copy_rtx_and_substitute (XEXP (orig, 1)));
                    974:                }
                    975:              temp = memory_address (mode, temp);
                    976:            }
                    977:          else
                    978:            temp = gen_rtx (PLUS, GET_MODE (orig),
                    979:                            copy_rtx_and_substitute (XEXP (orig, 0)),
                    980:                            copy_rtx_and_substitute (XEXP (orig, 1)));
                    981:        }
                    982:       else
                    983:        temp = gen_rtx (PLUS, GET_MODE (orig),
                    984:                        copy_rtx_and_substitute (XEXP (orig, 0)),
                    985:                        copy_rtx_and_substitute (XEXP (orig, 1)));
                    986: 
                    987:       return temp;
                    988:       
                    989:     case MEM:
                    990:       /* Take care of easiest case here.  */
                    991:       copy = XEXP (orig, 0);
                    992:       if (copy == frame_pointer_rtx || copy == arg_pointer_rtx)
                    993:        return gen_rtx (MEM, mode,
                    994:                        plus_constant (frame_pointer_rtx, fp_delta));
                    995:       if (GET_CODE (copy) == PLUS)
                    996:        {
                    997:          if (XEXP (copy, 0) == frame_pointer_rtx
                    998:              || XEXP (copy, 1) == frame_pointer_rtx
                    999:              || (ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
                   1000:                  && (XEXP (copy, 0) == arg_pointer_rtx
                   1001:                      || XEXP (copy, 1) == arg_pointer_rtx)))
                   1002:            {
                   1003:              rtx reg;
                   1004:              if (XEXP (copy, 0) == frame_pointer_rtx
                   1005:                  || XEXP (copy, 0) == arg_pointer_rtx)
                   1006:                reg = XEXP (copy, 0), copy = XEXP (copy, 1);
                   1007:              else
                   1008:                reg = XEXP (copy, 1), copy = XEXP (copy, 0);
                   1009: 
                   1010:              if (GET_CODE (copy) == CONST_INT)
                   1011:                {
                   1012:                  int c = INTVAL (copy);
                   1013: 
                   1014:                  if (reg == arg_pointer_rtx
                   1015:                      && c >= FIRST_PARM_OFFSET)
                   1016:                    {
                   1017:                      copy = parm_map[c / UNITS_PER_WORD];
                   1018: 
                   1019:                      /* If the MEM is only some of the bytes in the parm,
                   1020:                         truncate the parm value to the desired mode.  */
                   1021:                      if (GET_MODE (copy) != mode
                   1022:                          && GET_MODE (copy) != VOIDmode)
                   1023:                        return convert_to_mode (mode, copy, 0);
                   1024:                      return copy;
                   1025:                    }
                   1026:                  temp = gen_rtx (PLUS, Pmode,
                   1027:                                  frame_pointer_rtx,
                   1028:                                  gen_rtx (CONST_INT, SImode,
                   1029:                                           c + fp_delta));
                   1030:                  if (! memory_address_p (Pmode, temp))
                   1031:                    return gen_rtx (MEM, mode, plus_constant (inline_fp_rtx, c));
                   1032:                }
                   1033:              copy =  copy_rtx_and_substitute (copy);
                   1034:              temp = gen_rtx (PLUS, Pmode, frame_pointer_rtx, copy);
                   1035:              temp = plus_constant (temp, fp_delta);
                   1036:              temp = memory_address (Pmode, temp);
                   1037:            }
                   1038:          else if (reg_mentioned_p (frame_pointer_rtx, copy)
                   1039:                   || (ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
                   1040:                       && reg_mentioned_p (arg_pointer_rtx, copy)))
                   1041:            {
                   1042:              if (GET_CODE (XEXP (copy, 0)) == CONST_INT)
                   1043:                {
                   1044:                  temp = copy_rtx_and_substitute (XEXP (copy, 1));
                   1045:                  temp = plus_constant (temp, INTVAL (XEXP (copy, 0)));
                   1046:                }
                   1047:              else if (GET_CODE (XEXP (copy, 1)) == CONST_INT)
                   1048:                {
                   1049:                  temp = copy_rtx_and_substitute (XEXP (copy, 0));
                   1050:                  temp = plus_constant (temp, INTVAL (XEXP (copy, 1)));
                   1051:                }
                   1052:              else
                   1053:                {
                   1054:                  temp = gen_rtx (PLUS, GET_MODE (copy),
                   1055:                                  copy_rtx_and_substitute (XEXP (copy, 0)),
                   1056:                                  copy_rtx_and_substitute (XEXP (copy, 1)));
                   1057:                }
                   1058:            }
                   1059:          else
                   1060:            {
                   1061:              if (GET_CODE (XEXP (copy, 1)) == CONST_INT)
                   1062:                temp = plus_constant (copy_rtx_and_substitute (XEXP (copy, 0)),
                   1063:                                      INTVAL (XEXP (copy, 1)));
                   1064:              else if (GET_CODE (XEXP (copy, 0)) == CONST_INT)
                   1065:                temp = plus_constant (copy_rtx_and_substitute (XEXP (copy, 1)),
                   1066:                                      INTVAL (XEXP (copy, 0)));
                   1067:              else
                   1068:                {
                   1069:                  rtx left = copy_rtx_and_substitute (XEXP (copy, 0));
                   1070:                  rtx right = copy_rtx_and_substitute (XEXP (copy, 1));
                   1071: 
                   1072:                  temp = gen_rtx (PLUS, GET_MODE (copy), left, right);
                   1073:                }
                   1074:            }
                   1075:        }
                   1076:       else
                   1077:        temp = copy_rtx_and_substitute (copy);
                   1078: 
                   1079:       return change_address (orig, mode, temp);
                   1080: 
                   1081:     case RETURN:
                   1082:       abort ();
                   1083:     }
                   1084: 
                   1085:   copy = rtx_alloc (code);
                   1086:   PUT_MODE (copy, mode);
                   1087:   copy->in_struct = orig->in_struct;
                   1088:   copy->volatil = orig->volatil;
                   1089:   copy->unchanging = orig->unchanging;
                   1090: 
                   1091:   format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
                   1092: 
                   1093:   for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
                   1094:     {
                   1095:       rtx new;
                   1096: 
                   1097:       switch (*format_ptr++)
                   1098:        {
                   1099:        case 'u':
                   1100:        case '0':
                   1101:          break;
                   1102: 
                   1103:        case 'e':
                   1104:          XEXP (copy, i) = copy_rtx_and_substitute (XEXP (orig, i));
                   1105:          break;
                   1106: 
                   1107:        case 'E':
                   1108:          XVEC (copy, i) = XVEC (orig, i);
                   1109:          if (XVEC (orig, i) != NULL)
                   1110:            {
                   1111:              XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
                   1112:              for (j = 0; j < XVECLEN (copy, i); j++)
                   1113:                XVECEXP (copy, i, j) = copy_rtx_and_substitute (XVECEXP (orig, i, j));
                   1114:            }
                   1115:          break;
                   1116: 
                   1117:        case 'i':
                   1118:          XINT (copy, i) = XINT (orig, i);
                   1119:          break;
                   1120: 
                   1121:        case 's':
                   1122:          XSTR (copy, i) = XSTR (orig, i);
                   1123:          break;
                   1124: 
                   1125:        default:
                   1126:          fprintf (stderr,
                   1127:                   "switch format wrong in rtl2.copy_rtx_and_substitute(). format was: %c.\n",
                   1128:                   format_ptr[-1]);
                   1129:          abort ();
                   1130:        }
                   1131:     }
                   1132:   return copy;
                   1133: }
                   1134: 
                   1135: /* Attempt to simplify INSN while copying it from an inline fn,
                   1136:    assuming it is a SET that sets CC0.
                   1137: 
                   1138:    If we simplify it, we emit the appropriate insns and return
                   1139:    the last insn that we have handled (since we may handle the insn
                   1140:    that follows INSN as well as INSN itself).
                   1141: 
                   1142:    Otherwise we do nothing and return zero.  */
                   1143: 
                   1144: static rtx
                   1145: try_fold_cc0 (insn)
                   1146:      rtx insn;
                   1147: {
                   1148:   rtx cnst = copy_rtx_and_substitute (SET_SRC (PATTERN (insn)));
                   1149:   rtx pat, copy;
                   1150: 
                   1151:   if (CONSTANT_P (cnst)
                   1152:       /* @@ Cautious: Don't know how many of these tests we need.  */
                   1153:       && NEXT_INSN (insn)
                   1154:       && GET_CODE (pat = PATTERN (NEXT_INSN (insn))) == SET
                   1155:       && SET_DEST (pat) == pc_rtx
                   1156:       && GET_CODE (pat = SET_SRC (pat)) == IF_THEN_ELSE
                   1157:       && GET_RTX_LENGTH (GET_CODE (XEXP (pat, 0))) == 2)
                   1158:     {
                   1159:       rtx cnst2;
                   1160:       rtx cond = XEXP (pat, 0);
                   1161: 
                   1162:       if ((XEXP (cond, 0) == cc0_rtx
                   1163:           && CONSTANT_P (XEXP (cond, 1))
                   1164:           && (cnst2 = XEXP (cond, 1)))
                   1165:          || (XEXP (cond, 1) == cc0_rtx
                   1166:              && CONSTANT_P (XEXP (cond, 0))
                   1167:              && (cnst2 = XEXP (cond, 0))))
                   1168:        {
                   1169:          copy = fold_out_const_cc0 (cond, XEXP (pat, 1), XEXP (pat, 2),
                   1170:                                     cnst, cnst2);
                   1171:          if (copy)
                   1172:            {
                   1173:              if (GET_CODE (copy) == LABEL_REF)
                   1174:                {
                   1175:                  /* We will branch unconditionally to
                   1176:                     the label specified by COPY.
                   1177:                     Eliminate dead code by running down the
                   1178:                     list of insn until we see a CODE_LABEL.
                   1179:                     If the CODE_LABEL is the one specified
                   1180:                     by COPY, we win, and can delete all code
                   1181:                     up to (but not necessarily including)
                   1182:                     that label.  Otherwise only win a little:
                   1183:                     emit the branch insn, and continue expanding.  */
                   1184:                  rtx tmp = NEXT_INSN (insn);
                   1185:                  while (tmp && GET_CODE (tmp) != CODE_LABEL)
                   1186:                    tmp = NEXT_INSN (tmp);
                   1187:                  if (! tmp)
                   1188:                    abort ();
                   1189:                  if (label_map[CODE_LABEL_NUMBER (tmp)] == XEXP (copy, 0))
                   1190:                    {
                   1191:                      /* Big win.  */
                   1192:                      return PREV_INSN (tmp);
                   1193:                    }
                   1194:                  else
                   1195:                    {
                   1196:                      /* Small win.  Emit the unconditional branch,
                   1197:                         followed by a BARRIER, so that jump optimization
                   1198:                         will know what to do.  */
                   1199:                      emit_jump (copy);
                   1200:                      return NEXT_INSN (insn);
                   1201:                    }
                   1202:                }
                   1203:              else if (copy == pc_rtx)
                   1204:                {
                   1205:                  /* Do not take the branch, just fall through.
                   1206:                     Jump optimize should handle the elimination of
                   1207:                     dead code if appropriate.  */
                   1208:                  return NEXT_INSN (insn);
                   1209:                }
                   1210:              else
                   1211:                abort ();
                   1212:            }
                   1213:        }
                   1214:     }
                   1215:   return 0;
                   1216: }
                   1217: 
                   1218: /* If (COND_RTX CNST1 CNST2) yield a result we can treat
                   1219:    as being constant, return THEN_RTX if the result is always
                   1220:    non-zero, and return ELSE_RTX otherwise.  */
                   1221: static rtx
                   1222: fold_out_const_cc0 (cond_rtx, then_rtx, else_rtx, cnst1, cnst2)
                   1223:      rtx cond_rtx, then_rtx, else_rtx;
                   1224:      rtx cnst1, cnst2;
                   1225: {
                   1226:   int value1, value2;
                   1227:   int int1 = GET_CODE (cnst1) == CONST_INT;
                   1228:   int int2 = GET_CODE (cnst2) == CONST_INT;
                   1229:   if (int1)
                   1230:     value1 = INTVAL (cnst1);
                   1231:   else
                   1232:     value1 = 1;
                   1233:   if (int2)
                   1234:     value2 = INTVAL (cnst2);
                   1235:   else
                   1236:     value2 = 1;
                   1237: 
                   1238:   switch (GET_CODE (cond_rtx))
                   1239:     {
                   1240:     case NE:
                   1241:       if (int1 && int2)
                   1242:        if (value1 != value2)
                   1243:          return copy_rtx_and_substitute (then_rtx);
                   1244:        else
                   1245:          return copy_rtx_and_substitute (else_rtx);
                   1246:       if (value1 == 0 || value2 == 0)
                   1247:        return copy_rtx_and_substitute (then_rtx);
                   1248:       if (int1 == 0 && int2 == 0)
                   1249:        if (rtx_equal_p (cnst1, cnst2))
                   1250:          return copy_rtx_and_substitute (else_rtx);
                   1251:       break;
                   1252:     case EQ:
                   1253:       if (int1 && int2)
                   1254:        if (value1 == value2)
                   1255:          return copy_rtx_and_substitute (then_rtx);
                   1256:        else
                   1257:          return copy_rtx_and_substitute (else_rtx);
                   1258:       if (value1 == 0 || value2 == 0)
                   1259:        return copy_rtx_and_substitute (else_rtx);
                   1260:       if (int1 == 0 && int2 == 0)
                   1261:        if (rtx_equal_p (cnst1, cnst2))
                   1262:          return copy_rtx_and_substitute (then_rtx);
                   1263:       break;
                   1264:     case GE:
                   1265:       if (int1 && int2)
                   1266:        if (value1 >= value2)
                   1267:          return copy_rtx_and_substitute (then_rtx);
                   1268:        else
                   1269:          return copy_rtx_and_substitute (else_rtx);
                   1270:       if (value1 == 0)
                   1271:        return copy_rtx_and_substitute (else_rtx);
                   1272:       if (value2 == 0)
                   1273:        return copy_rtx_and_substitute (then_rtx);
                   1274:       break;
                   1275:     case GT:
                   1276:       if (int1 && int2)
                   1277:        if (value1 > value2)
                   1278:          return copy_rtx_and_substitute (then_rtx);
                   1279:        else
                   1280:          return copy_rtx_and_substitute (else_rtx);
                   1281:       if (value1 == 0)
                   1282:        return copy_rtx_and_substitute (else_rtx);
                   1283:       if (value2 == 0)
                   1284:        return copy_rtx_and_substitute (then_rtx);
                   1285:       break;
                   1286:     case LE:
                   1287:       if (int1 && int2)
                   1288:        if (value1 <= value2)
                   1289:          return copy_rtx_and_substitute (then_rtx);
                   1290:        else
                   1291:          return copy_rtx_and_substitute (else_rtx);
                   1292:       if (value1 == 0)
                   1293:        return copy_rtx_and_substitute (then_rtx);
                   1294:       if (value2 == 0)
                   1295:        return copy_rtx_and_substitute (else_rtx);
                   1296:       break;
                   1297:     case LT:
                   1298:       if (int1 && int2)
                   1299:        if (value1 < value2)
                   1300:          return copy_rtx_and_substitute (then_rtx);
                   1301:        else
                   1302:          return copy_rtx_and_substitute (else_rtx);
                   1303:       if (value1 == 0)
                   1304:        return copy_rtx_and_substitute (then_rtx);
                   1305:       if (value2 == 0)
                   1306:        return copy_rtx_and_substitute (else_rtx);
                   1307:       break;
                   1308:     case GEU:
                   1309:       if (int1 && int2)
                   1310:        if ((unsigned)value1 >= (unsigned)value2)
                   1311:          return copy_rtx_and_substitute (then_rtx);
                   1312:        else
                   1313:          return copy_rtx_and_substitute (else_rtx);
                   1314:       if (value1 == 0)
                   1315:        return copy_rtx_and_substitute (else_rtx);
                   1316:       if (value2 == 0)
                   1317:        return copy_rtx_and_substitute (then_rtx);
                   1318:       break;
                   1319:     case GTU:
                   1320:       if (int1 && int2)
                   1321:        if ((unsigned)value1 > (unsigned)value2)
                   1322:          return copy_rtx_and_substitute (then_rtx);
                   1323:        else
                   1324:          return copy_rtx_and_substitute (else_rtx);
                   1325:       if (value1 == 0)
                   1326:        return copy_rtx_and_substitute (else_rtx);
                   1327:       if (value2 == 0)
                   1328:        return copy_rtx_and_substitute (then_rtx);
                   1329:       break;
                   1330:     case LEU:
                   1331:       if (int1 && int2)
                   1332:        if ((unsigned)value1 <= (unsigned)value2)
                   1333:          return copy_rtx_and_substitute (then_rtx);
                   1334:        else
                   1335:          return copy_rtx_and_substitute (else_rtx);
                   1336:       if (value1 == 0)
                   1337:        return copy_rtx_and_substitute (then_rtx);
                   1338:       if (value2 == 0)
                   1339:        return copy_rtx_and_substitute (else_rtx);
                   1340:       break;
                   1341:     case LTU:
                   1342:       if (int1 && int2)
                   1343:        if ((unsigned)value1 < (unsigned)value2)
                   1344:          return copy_rtx_and_substitute (then_rtx);
                   1345:        else
                   1346:          return copy_rtx_and_substitute (else_rtx);
                   1347:       if (value1 == 0)
                   1348:        return copy_rtx_and_substitute (then_rtx);
                   1349:       if (value2 == 0)
                   1350:        return copy_rtx_and_substitute (else_rtx);
                   1351:       break;
                   1352:     }
                   1353:   /* Could not hack it.  */
                   1354:   return 0;
                   1355: }
                   1356: 
                   1357: /* Output the assembly language code for the function FNDECL
                   1358:    from its DECL_SAVED_INSNS.  Used for inline functions that are output
                   1359:    at end of compilation instead of where they came in the source.  */
                   1360: 
                   1361: void
                   1362: output_inline_function (fndecl)
                   1363:      tree fndecl;
                   1364: {
                   1365:   rtx head = DECL_SAVED_INSNS (fndecl);
                   1366:   rtx last;
                   1367: 
                   1368:   temporary_allocation ();
                   1369: 
                   1370:   /* This call is only used to initialize global variables.
                   1371:      The rtl code it emits will be discarded below.  */
                   1372:   expand_function_start (fndecl);
                   1373: 
                   1374:   /* Set stack frame size.  */
                   1375:   assign_stack_local (BLKmode, DECL_FRAME_SIZE (fndecl));
                   1376: 
                   1377:   restore_reg_data (FIRST_PARM_INSN (head));
                   1378: 
                   1379:   expand_function_end (fndecl);
                   1380: 
                   1381:   for (last = head; NEXT_INSN (last); last = NEXT_INSN (last))
                   1382:     ;
                   1383: 
                   1384:   set_new_first_and_last_insn (FIRST_PARM_INSN (head), last);
                   1385: 
                   1386:   /* Compile this function all the way down to assembly code.  */
                   1387:   rest_of_compilation (fndecl);
                   1388: 
                   1389:   permanent_allocation ();
                   1390: }

unix.superglobalmegacorp.com

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