Annotation of gcc/integrate.c, revision 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.