Annotation of gcc/integrate.c, revision 1.1.1.11

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: 
                     26: #include "config.h"
                     27: #include "rtl.h"
                     28: #include "tree.h"
                     29: #include "flags.h"
                     30: #include "insn-flags.h"
                     31: #include "expr.h"
                     32: 
                     33: #include "obstack.h"
                     34: #define        obstack_chunk_alloc     xmalloc
                     35: #define        obstack_chunk_free      free
                     36: extern int xmalloc ();
                     37: extern void free ();
                     38: 
                     39: extern struct obstack permanent_obstack, maybepermanent_obstack;
                     40: extern struct obstack *rtl_obstack, *saveable_obstack, *current_obstack;
                     41: 
                     42: #define MIN(x,y) ((x < y) ? x : y)
                     43: 
                     44: extern tree pushdecl ();
1.1.1.5   root       45: 
                     46: /* Default max number of insns a function can have and still be inline.
                     47:    This is overridden on RISC machines.  */
                     48: #ifndef INTEGRATE_THRESHOLD
                     49: #define INTEGRATE_THRESHOLD(DECL) \
                     50:   (8 * (8 + list_length (DECL_ARGUMENTS (DECL)) + 16*TREE_INLINE (DECL)))
                     51: #endif
1.1       root       52: 
                     53: /* This is the target of the inline function being expanded,
                     54:    or NULL if there is none.  */
                     55: static rtx inline_target;
                     56: 
                     57: /* We must take special care not to disrupt life too severely
                     58:    when performing procedure integration.  One thing that that
                     59:    involves is not creating illegitimate address which reload
                     60:    cannot fix.  Since we don't know what the frame pointer is
                     61:    not capable of (in a machine independent way), we create
                     62:    a pseudo-frame pointer which will have to do for now.  */
                     63: static rtx inline_fp_rtx;
                     64: 
                     65: /* Convert old frame-pointer offsets to new.  Parameters which only
                     66:    produce values (no addresses, and are never assigned), map directly
                     67:    to the pseudo-reg of the incoming value.  Parameters that are
                     68:    assigned to but do not have their address taken are given a fresh
                     69:    pseudo-register.  Parameters that have their address take are
                     70:    given a fresh stack-slot.  */
                     71: static rtx *parm_map;
                     72: 
                     73: /* ?? Should this be done here??  It is not right now.
                     74:    Keep track of whether a given pseudo-register is the sum
                     75:    of the frame pointer and a const_int (or zero).  */
                     76: static char *fp_addr_p;
                     77: 
                     78: /* For the local variables of the procdure being integrated that live
                     79:    on the frame, FRAME_POINTER_DELTA says how much to change their
                     80:    offsets by, so that they now live in the correct place on the
                     81:    frame of the function being compiled.  */
                     82: static int fp_delta;
                     83: 
1.1.1.11! root       84: /* When an insn is being copied by copy_rtx_and_substitute,
        !            85:    this is nonzero if we have copied an ASM_OPERANDS.
        !            86:    In that case, it is the original input-operand vector.
        !            87:    Likewise in copy_for_inline.  */
        !            88: static rtvec orig_asm_operands_vector;
        !            89: 
        !            90: /* When an insn is being copied by copy_rtx_and_substitute,
        !            91:    this is nonzero if we have copied an ASM_OPERANDS.
        !            92:    In that case, it is the copied input-operand vector.
        !            93:    Likewise in copy_for_inline.  */
        !            94: static rtvec copy_asm_operands_vector;
        !            95: 
1.1       root       96: /* Return a copy of an rtx (as needed), substituting pseudo-register,
                     97:    labels, and frame-pointer offsets as necessary.  */
                     98: static rtx copy_rtx_and_substitute ();
1.1.1.7   root       99: /* Variant, used for memory addresses that are not memory_address_p.  */
                    100: static rtx copy_address ();
1.1       root      101: 
                    102: static void copy_parm_decls ();
                    103: static void copy_decl_tree ();
                    104: 
                    105: static rtx try_fold_cc0 ();
                    106: 
                    107: /* We do some simple constant folding optimization.  This optimization
                    108:    really exists primarily to save time inlining a function.  It
1.1.1.5   root      109:    also helps users who ask for inline functions without -O.  */
1.1       root      110: static rtx fold_out_const_cc0 ();
                    111: 
                    112: /* Zero if the current function (whose FUNCTION_DECL is FNDECL)
                    113:    is safe and reasonable to integrate into other functions.
                    114:    Nonzero means value is a warning message with a single %s
                    115:    for the function's name.  */
                    116: 
                    117: char *
                    118: function_cannot_inline_p (fndecl)
                    119:      register tree fndecl;
                    120: {
                    121:   register rtx insn;
                    122:   tree last = tree_last (TYPE_ARG_TYPES (TREE_TYPE (fndecl)));
1.1.1.5   root      123:   int max_insns = INTEGRATE_THRESHOLD (fndecl);
1.1       root      124:   register int ninsns = 0;
                    125:   register tree parms;
                    126: 
                    127:   /* No inlines with varargs.  `grokdeclarator' gives a warning
                    128:      message about that if `inline' is specified.  This code
                    129:      it put in to catch the volunteers.  */
                    130:   if (last && TREE_VALUE (last) != void_type_node)
1.1.1.7   root      131:     return "varargs function cannot be inline";
1.1       root      132: 
                    133:   /* If its not even close, don't even look.  */
                    134:   if (get_max_uid () > 2 * max_insns)
1.1.1.7   root      135:     return "function too large to be inline";
1.1       root      136: 
1.1.1.11! root      137:   /* If the structure value address comes in the stack,
        !           138:      we can't handle it.  */
        !           139: #if defined (STRUCT_VALUE) || defined (STRUCT_VALUE_INCOMING)
        !           140:   if (TYPE_MODE (TREE_TYPE (TREE_TYPE (fndecl))) == BLKmode)
        !           141:     return "function returning large aggregate cannot be inline";
        !           142: #endif
        !           143: 
1.1       root      144:   /* Don't inline functions which have BLKmode arguments.
                    145:      Don't inline functions that take the address of
                    146:        a parameter and do not specify a function prototype.  */
                    147:   for (parms = DECL_ARGUMENTS (fndecl); parms; parms = TREE_CHAIN (parms))
                    148:     {
                    149:       if (TYPE_MODE (TREE_TYPE (parms)) == BLKmode)
1.1.1.7   root      150:        return "function with large aggregate parameter cannot be inline";
1.1       root      151:       if (last == NULL_TREE && TREE_ADDRESSABLE (parms))
1.1.1.7   root      152:        return "no prototype, and parameter address used; cannot be inline";
1.1.1.11! root      153:       /* If an aggregate is thought of as "in memory"
        !           154:         then its components are referred to by narrower memory refs.
        !           155:         If the actual parameter is a reg, these refs can't be translated,
        !           156:         esp. since copy_rtx_and_substitute doesn't know whether it is
        !           157:         reading or writing.  */
        !           158:       if ((TREE_CODE (TREE_TYPE (parms)) == RECORD_TYPE
        !           159:           || TREE_CODE (TREE_TYPE (parms)) == UNION_TYPE)
        !           160:          && GET_CODE (DECL_RTL (parms)) == MEM)
        !           161:        return "address of an aggregate parameter is used; cannot be inline";
1.1       root      162:     }
                    163: 
                    164:   if (get_max_uid () > max_insns)
                    165:     {
                    166:       for (ninsns = 0, insn = get_first_nonparm_insn (); insn && ninsns < max_insns;
                    167:           insn = NEXT_INSN (insn))
                    168:        {
                    169:          if (GET_CODE (insn) == INSN
                    170:              || GET_CODE (insn) == JUMP_INSN
                    171:              || GET_CODE (insn) == CALL_INSN)
                    172:            ninsns++;
                    173:        }
                    174: 
                    175:       if (ninsns >= max_insns)
1.1.1.7   root      176:        return "function too large to be inline";
1.1       root      177:     }
                    178: 
                    179:   return 0;
                    180: }
                    181: 
                    182: /* Variables used within save_for_inline.  */
                    183: 
                    184: /* Mapping from old pesudo-register to new pseudo-registers.
                    185:    The first element of this map is reg_map[FIRST_PSEUDO_REGISTER].
1.1.1.6   root      186:    It is allocated in `save_for_inline' and `expand_inline_function',
1.1       root      187:    and deallocated on exit from each of those routines.  */
                    188: static rtx *reg_map;
                    189: 
                    190: /* Mapping from old code-labels to new code-labels.
                    191:    The first element of this map is label_map[min_labelno].
1.1.1.6   root      192:    It is allocated in `save_for_inline' and `expand_inline_function',
1.1       root      193:    and deallocated on exit from each of those routines.  */
                    194: static rtx *label_map;
                    195: 
1.1.1.6   root      196: /* Mapping from old insn uid's to copied insns.
                    197:    It is allocated in `save_for_inline' and `expand_inline_function',
                    198:    and deallocated on exit from each of those routines.  */
                    199: static rtx *insn_map;
                    200: 
1.1       root      201: /* Map pseudo reg number into the PARM_DECL for the parm living in the reg.
                    202:    Zero for a reg that isn't a parm's home.
                    203:    Only reg numbers less than max_parm_reg are mapped here.  */
                    204: static tree *parmdecl_map;
                    205: 
                    206: /* Keep track of first pseudo-register beyond those that are parms.  */
                    207: static int max_parm_reg;
                    208: 
1.1.1.7   root      209: /* Offset from arg ptr to the first parm of this inline function.  */
                    210: static int first_parm_offset;
                    211: 
1.1       root      212: /* On machines that perform a function return with a single
                    213:    instruction, such as the VAX, these return insns must be
                    214:    mapped into branch statements.  */
                    215: extern rtx return_label;
                    216: 
                    217: /* Copy an rtx for save_for_inline.  */
                    218: static rtx copy_for_inline ();
                    219: 
                    220: /* Make the insns and PARM_DECLs of the current function permanent
                    221:    and record other information in DECL_SAVED_INSNS to allow inlining
                    222:    of this function in subsequent calls.  */
                    223: 
                    224: void
                    225: save_for_inline (fndecl)
                    226:      tree fndecl;
                    227: {
                    228:   extern rtx *regno_reg_rtx;   /* in emit-rtl.c.  */
                    229:   extern current_function_args_size;
                    230: 
                    231:   rtx first_insn, last_insn, insn;
                    232:   rtx head, copy;
                    233:   tree parms;
                    234:   int max_labelno, min_labelno, i, len;
                    235:   int max_reg;
1.1.1.6   root      236:   int max_uid;
1.1       root      237: 
                    238:   /* Make and emit a return-label if we have not already done so.  */
                    239: 
                    240:   if (return_label == 0)
                    241:     {
                    242:       return_label = gen_label_rtx ();
                    243:       emit_label (return_label);
                    244:     }
                    245: 
                    246:   /* Get some bounds on the labels and registers used.  */
                    247: 
                    248:   max_labelno = max_label_num ();
                    249:   min_labelno = get_first_label_num ();
                    250:   max_parm_reg = max_parm_reg_num ();
                    251:   max_reg = max_reg_num ();
                    252: 
                    253:   /* Set up PARMDECL_MAP which maps pseudo-reg number to its PARM_DECL.
                    254: 
                    255:      Set TREE_VOLATILE to 0 if the parm is in a register, otherwise 1.
                    256:      Later we set TREE_READONLY to 0 if the parm is modified inside the fn.  */
                    257: 
                    258:   parmdecl_map = (tree *) alloca (max_parm_reg * sizeof (tree));
1.1.1.3   root      259:   bzero (parmdecl_map, max_parm_reg * sizeof (tree));
1.1       root      260: 
                    261:   for (parms = DECL_ARGUMENTS (fndecl); parms; parms = TREE_CHAIN (parms))
                    262:     {
                    263:       rtx p = DECL_RTL (parms);
                    264: 
                    265:       if (GET_CODE (p) == REG)
                    266:        {
                    267:          parmdecl_map[REGNO (p)] = parms;
                    268:          TREE_VOLATILE (parms) = 0;
                    269:        }
                    270:       else
                    271:        TREE_VOLATILE (parms) = 1;
                    272:       TREE_READONLY (parms) = 1;
                    273:     }
                    274: 
                    275:   /* The list of DECL_SAVES_INSNS, starts off with a header which
                    276:      contains the following information:
                    277: 
                    278:      the first insn of the function (not including the insns that copy
                    279:      parameters into registers).
                    280:      the first label used by that function,
                    281:      the last label used by that function,
                    282:      and the total number of registers used.  */
                    283: 
                    284:   head = gen_inline_header_rtx (NULL, NULL, min_labelno, max_labelno,
                    285:                                max_parm_reg, max_reg,
                    286:                                current_function_args_size);
1.1.1.6   root      287:   max_uid = INSN_UID (head);
1.1       root      288: 
                    289:   /* We have now allocated all that needs to be allocated permanently
                    290:      on the rtx obstack.  Set our high-water mark, so that we
                    291:      can free the rest of this when the time comes.  */
                    292: 
                    293:   preserve_data ();
                    294: 
                    295:   /* Copy the chain insns of this function.
                    296:      Install the copied chain as the insns of this function,
                    297:      for continued compilation;
                    298:      the original chain is recorded as the DECL_SAVED_INSNS
                    299:      for inlining future calls.  */
                    300: 
                    301:   /* If there are insns that copy parms from the stack into pseudo registers,
                    302:      those insns are not copied.  `expand_inline_function' must
                    303:      emit the correct code to handle such things.  */
                    304: 
                    305:   insn = get_insns ();
                    306:   if (GET_CODE (insn) != NOTE)
                    307:     abort ();
                    308:   first_insn = rtx_alloc (NOTE);
                    309:   NOTE_SOURCE_FILE (first_insn) = NOTE_SOURCE_FILE (insn);
                    310:   NOTE_LINE_NUMBER (first_insn) = NOTE_LINE_NUMBER (insn);
                    311:   INSN_UID (first_insn) = INSN_UID (insn);
                    312:   PREV_INSN (first_insn) = NULL;
                    313:   NEXT_INSN (first_insn) = NULL;
                    314:   last_insn = first_insn;
                    315: 
                    316:   /* Each pseudo-reg in the old insn chain must have a unique rtx in the copy.
                    317:      Make these new rtx's now, and install them in regno_reg_rtx, so they
                    318:      will be the official pseudo-reg rtx's for the rest of compilation.  */
                    319: 
                    320:   reg_map = (rtx *) alloca ((max_reg + 1) * sizeof (rtx));
                    321: 
                    322:   len = sizeof (struct rtx_def) + (GET_RTX_LENGTH (REG) - 1) * sizeof (rtunion);
                    323:   for (i = max_reg - 1; i >= FIRST_PSEUDO_REGISTER; i--)
                    324:     reg_map[i] = (rtx)obstack_copy (&maybepermanent_obstack, regno_reg_rtx[i], len);
                    325:   bcopy (reg_map + FIRST_PSEUDO_REGISTER,
                    326:         regno_reg_rtx + FIRST_PSEUDO_REGISTER,
1.1.1.7   root      327:         (max_reg - FIRST_PSEUDO_REGISTER) * sizeof (rtx));
1.1       root      328: 
                    329:   /* Likewise each label rtx must have a unique rtx as its copy.  */
                    330: 
                    331:   label_map = (rtx *)alloca ((max_labelno - min_labelno) * sizeof (rtx));
                    332:   label_map -= min_labelno;
                    333: 
                    334:   for (i = min_labelno; i < max_labelno; i++)
                    335:     label_map[i] = gen_label_rtx ();
                    336: 
1.1.1.6   root      337:   /* Record the mapping of old insns to copied insns.  */
                    338: 
                    339:   insn_map = (rtx *) alloca (max_uid * sizeof (rtx));
                    340:   bzero (insn_map, max_uid * sizeof (rtx));
                    341: 
1.1       root      342:   /* Now copy the chain of insns.  */
                    343: 
                    344:   for (insn = NEXT_INSN (insn); insn; insn = NEXT_INSN (insn))
                    345:     {
1.1.1.11! root      346:       orig_asm_operands_vector = 0;
        !           347:       copy_asm_operands_vector = 0;
        !           348: 
1.1       root      349:       switch (GET_CODE (insn))
                    350:        {
                    351:        case NOTE:
1.1.1.7   root      352:          if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_END)
                    353:            continue;
                    354: 
1.1       root      355:          copy = rtx_alloc (NOTE);
                    356:          NOTE_SOURCE_FILE (copy) = NOTE_SOURCE_FILE (insn);
                    357:          NOTE_LINE_NUMBER (copy) = NOTE_LINE_NUMBER (insn);
                    358:          break;
                    359: 
                    360:        case INSN:
                    361:        case CALL_INSN:
                    362:        case JUMP_INSN:
                    363:          copy = rtx_alloc (GET_CODE (insn));
                    364:          PATTERN (copy) = copy_for_inline (PATTERN (insn));
                    365:          INSN_CODE (copy) = -1;
                    366:          LOG_LINKS (copy) = NULL;
                    367:          REG_NOTES (copy) = copy_for_inline (REG_NOTES (insn));
                    368:          break;
                    369: 
                    370:        case CODE_LABEL:
                    371:          copy = label_map[CODE_LABEL_NUMBER (insn)];
                    372:          break;
                    373: 
                    374:        case BARRIER:
                    375:          copy = rtx_alloc (BARRIER);
                    376:          break;
                    377: 
                    378:        default:
                    379:          abort ();
                    380:        }
                    381:       INSN_UID (copy) = INSN_UID (insn);
1.1.1.6   root      382:       insn_map[INSN_UID (insn)] = copy;
1.1       root      383:       NEXT_INSN (last_insn) = copy;
                    384:       PREV_INSN (copy) = last_insn;
                    385:       last_insn = copy;
                    386:     }
                    387: 
                    388:   NEXT_INSN (last_insn) = NULL;
                    389: 
                    390:   NEXT_INSN (head) = get_first_nonparm_insn ();
                    391:   FIRST_PARM_INSN (head) = get_insns ();
                    392:   DECL_SAVED_INSNS (fndecl) = head;
                    393:   DECL_FRAME_SIZE (fndecl) = get_frame_size ();
                    394:   TREE_INLINE (fndecl) = 1;
                    395: 
                    396:   parmdecl_map = 0;
                    397:   label_map = 0;
                    398:   reg_map = 0;
                    399:   return_label = 0;
                    400: 
                    401:   set_new_first_and_last_insn (first_insn, last_insn);
                    402: }
                    403: 
                    404: /* Copy the rtx ORIG recursively, replacing pseudo-regs and labels
                    405:    according to `reg_map' and `label_map'.
                    406:    All other kinds of rtx are copied except those that can never be
                    407:    changed during compilation.  */
                    408: 
                    409: static rtx
                    410: copy_for_inline (orig)
                    411:      rtx orig;
                    412: {
                    413:   register rtx x = orig;
                    414:   register int i;
                    415:   register enum rtx_code code;
                    416:   register char *format_ptr;
                    417: 
                    418:   if (x == 0)
                    419:     return x;
                    420: 
                    421:   code = GET_CODE (x);
                    422: 
                    423:   /* These types may be freely shared.  */
                    424: 
                    425:   switch (code)
                    426:     {
                    427:     case QUEUED:
                    428:     case CONST_INT:
                    429:     case CONST_DOUBLE:
                    430:     case SYMBOL_REF:
                    431:     case PC:
                    432:     case CC0:
                    433:       return x;
                    434: 
1.1.1.11! root      435:     case ASM_OPERANDS:
        !           436:       /* If a single asm insn contains multiple output operands
        !           437:         then it contains multiple ASM_OPERANDS rtx's that share operand 3.
        !           438:         We must make sure that the copied insn continues to share it.  */
        !           439:       if (orig_asm_operands_vector == XVEC (orig, 3))
        !           440:        {
        !           441:          x = rtx_alloc (ASM_OPERANDS);
        !           442:          XSTR (x, 0) = XSTR (orig, 0);
        !           443:          XSTR (x, 1) = XSTR (orig, 1);
        !           444:          XINT (x, 2) = XINT (orig, 2);
        !           445:          XVEC (x, 3) = copy_asm_operands_vector;
        !           446:          XVEC (x, 4) = XVEC (orig, 4);
        !           447:          return x;
        !           448:        }
        !           449:       break;
        !           450: 
1.1       root      451:     case MEM:
                    452:       /* A MEM is allowed to be shared if its address is constant
                    453:         or is a constant plus one of the special registers.  */
                    454:       if (CONSTANT_ADDRESS_P (XEXP (x, 0)))
                    455:        return x;
                    456:       if (GET_CODE (XEXP (x, 0)) == PLUS
                    457:          && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
                    458:          && (REGNO (XEXP (XEXP (x, 0), 0)) == FRAME_POINTER_REGNUM
                    459:              || REGNO (XEXP (XEXP (x, 0), 0)) == ARG_POINTER_REGNUM)
                    460:          && CONSTANT_ADDRESS_P (XEXP (XEXP (x, 0), 1)))
                    461:        if (GET_CODE (XEXP (x, 0)) == REG
                    462:            && (REGNO (XEXP (x, 0)) == FRAME_POINTER_REGNUM
                    463:                || REGNO (XEXP (x, 0)) == ARG_POINTER_REGNUM)
                    464:            && CONSTANT_ADDRESS_P (XEXP (x, 1)))
                    465:        return x;
                    466:       break;
                    467: 
                    468:     case LABEL_REF:
                    469:       {
                    470:        /* Must point to the new insn.  */
                    471:        return gen_rtx (LABEL_REF, GET_MODE (orig),
                    472:                        label_map[CODE_LABEL_NUMBER (XEXP (orig, 0))]);
                    473:       }
                    474: 
                    475:     case REG:
                    476:       if (REGNO (x) >= FIRST_PSEUDO_REGISTER)
                    477:        return reg_map [REGNO (x)];
                    478:       else
                    479:        return x;
                    480: 
                    481:       /* If a parm that gets modified lives in a pseudo-reg,
                    482:         set its TREE_VOLATILE to prevent certain optimizations.  */
                    483:     case SET:
                    484:       {
                    485:        rtx dest = SET_DEST (x);
                    486: 
                    487:        if (GET_CODE (dest) == REG
                    488:            && REGNO (dest) < max_parm_reg
1.1.1.3   root      489:            && REGNO (dest) >= FIRST_PSEUDO_REGISTER
                    490:            && parmdecl_map[REGNO (dest)] != 0)
1.1       root      491:          TREE_READONLY (parmdecl_map[REGNO (dest)]) = 0;
                    492:       }
                    493:       break;
                    494:     }
                    495: 
                    496:   /* Replace this rtx with a copy of itself.  */
                    497: 
                    498:   x = rtx_alloc (code);
                    499:   bcopy (orig, x, sizeof (int) * (GET_RTX_LENGTH (code) + 1));
                    500: 
                    501:   /* Now scan the subexpressions recursively.
                    502:      We can store any replaced subexpressions directly into X
                    503:      since we know X is not shared!  Any vectors in X
                    504:      must be copied if X was copied.  */
                    505: 
                    506:   format_ptr = GET_RTX_FORMAT (code);
                    507: 
                    508:   for (i = 0; i < GET_RTX_LENGTH (code); i++)
                    509:     {
                    510:       switch (*format_ptr++)
                    511:        {
                    512:        case 'e':
                    513:          XEXP (x, i) = copy_for_inline (XEXP (x, i));
                    514:          break;
                    515: 
1.1.1.6   root      516:        case 'u':
                    517:          /* Change any references to old-insns to point to the
                    518:             corresponding copied insns.  */
                    519:          return insn_map[INSN_UID (XEXP (x, i))];
                    520: 
1.1       root      521:        case 'E':
1.1.1.6   root      522:          if (XVEC (x, i) != NULL && XVECLEN (x, i) != 0)
1.1       root      523:            {
                    524:              register int j;
                    525: 
                    526:              XVEC (x, i) = gen_rtvec_v (XVECLEN (x, i), &XVECEXP (x, i, 0));
                    527:              for (j = 0; j < XVECLEN (x, i); j++)
                    528:                XVECEXP (x, i, j)
                    529:                  = copy_for_inline (XVECEXP (x, i, j));
                    530:            }
                    531:          break;
                    532:        }
                    533:     }
1.1.1.11! root      534: 
        !           535:   if (code == ASM_OPERANDS && orig_asm_operands_vector == 0)
        !           536:     {
        !           537:       orig_asm_operands_vector = XVEC (orig, 3);
        !           538:       copy_asm_operands_vector = XVEC (x, 3);
        !           539:     }
        !           540: 
1.1       root      541:   return x;
                    542: }
                    543: 
                    544: /* Integrate the procedure defined by FNDECL.  Note that this function
                    545:    may wind up calling itself.  Since the static variables are not
                    546:    reentrant, we do not assign them until after the possibility
                    547:    or recursion is eliminated.
                    548: 
                    549:    If IGNORE is nonzero, do not produce a value.
                    550:    Otherwise store the value in TARGET if it is nonzero and that is convenient.
                    551: 
                    552:    Value is:
                    553:    (rtx)-1 if we could not substitute the function
                    554:    0 if we substituted it and it does not produce a value
                    555:    else an rtx for where the value is stored.  */
                    556: 
                    557: rtx
                    558: expand_inline_function (fndecl, parms, target, ignore, type, structure_value_addr)
                    559:      tree fndecl, parms;
                    560:      rtx target;
                    561:      int ignore;
                    562:      tree type;
                    563:      rtx structure_value_addr;
                    564: {
                    565:   tree formal, actual;
                    566:   rtx header = DECL_SAVED_INSNS (fndecl);
                    567:   rtx insns = FIRST_FUNCTION_INSN (header);
1.1.1.9   root      568:   rtx insn;
1.1       root      569:   int max_regno = MAX_REGNUM (header) + 1;
                    570:   register int i;
                    571:   int min_labelno = FIRST_LABELNO (header);
                    572:   int max_labelno = LAST_LABELNO (header);
                    573:   int nargs;
                    574:   rtx *arg_vec;
1.1.1.9   root      575:   rtx local_return_label = 0;
1.1       root      576:   rtx follows_call = 0;
1.1.1.7   root      577:   rtx this_struct_value_rtx = 0;
1.1       root      578: 
                    579:   if (max_regno < FIRST_PSEUDO_REGISTER)
1.1.1.3   root      580:     abort ();
1.1       root      581: 
                    582:   nargs = list_length (DECL_ARGUMENTS (fndecl));
                    583: 
1.1.1.7   root      584:   first_parm_offset = FIRST_PARM_OFFSET (fndecl);
                    585: 
1.1       root      586:   /* We expect PARMS to have the right length; don't crash if not.  */
                    587:   if (list_length (parms) != nargs)
                    588:     return (rtx)-1;
                    589: 
                    590:   /* Make a fresh binding contour that we can easily remove.  */
                    591:   pushlevel (0);
                    592:   expand_start_bindings (0);
                    593: 
                    594:   /* Get all the actual args as RTL, and store them in ARG_VEC.  */
                    595: 
                    596:   arg_vec = (rtx *)alloca (nargs * sizeof (rtx));
                    597: 
                    598:   for (formal = DECL_ARGUMENTS (fndecl),
                    599:        actual = parms,
                    600:        i = 0;
                    601:        formal;
                    602:        formal = TREE_CHAIN (formal),
                    603:        actual = TREE_CHAIN (actual),
                    604:        i++)
                    605:     {
                    606:       tree arg = TREE_VALUE (actual); /* this has already been converted */
                    607:       enum machine_mode tmode = TYPE_MODE (TREE_TYPE (formal));
                    608:       rtx copy;
                    609: 
1.1.1.7   root      610:       emit_note (DECL_SOURCE_FILE (formal), DECL_SOURCE_LINE (formal));
1.1       root      611: 
                    612:       if (TREE_ADDRESSABLE (formal))
                    613:        {
                    614:          int size = int_size_in_bytes (TREE_TYPE (formal));
                    615:          copy = assign_stack_local (tmode, size);
                    616:          store_expr (arg, copy, 0);
                    617:        }
                    618:       else if (! TREE_READONLY (formal)
                    619:               || TREE_VOLATILE (formal))
                    620:        {
                    621:          /* If parm is modified or if it hasn't a pseudo reg,
                    622:             we may not simply substitute the actual value;
                    623:             copy it through a register.  */
                    624:          copy = gen_reg_rtx (tmode);
                    625:          store_expr (arg, copy, 0);
                    626:        }
                    627:       else
                    628:        {
                    629:          copy = expand_expr (arg, 0, tmode, 0);
                    630: 
                    631:          /* We do not use CONSTANT_ADDRESS_P here because
                    632:             the set of cases where that might make a difference
                    633:             are a subset of the cases that arise even when
                    634:             it is a CONSTANT_ADDRESS_P (i.e., fp_delta
                    635:             gets into the act.  */
                    636:          if (GET_CODE (copy) != REG && ! CONSTANT_P (copy))
                    637:            copy = copy_to_reg (copy);
                    638:        }
                    639:       arg_vec[i] = copy;
                    640:     }
                    641: 
                    642:   copy_parm_decls (DECL_ARGUMENTS (fndecl), arg_vec);
                    643: 
                    644:   /* Perform postincrements before actually calling the function.  */
                    645:   emit_queue ();
                    646: 
                    647:   /* clean up stack so that variables might have smaller offsets.  */
                    648:   do_pending_stack_adjust ();
                    649: 
                    650:   /* Pass the function the address in which to return a structure value.  */
                    651:   if (structure_value_addr)
1.1.1.7   root      652:     {
                    653:       if (GET_CODE (struct_value_rtx) == MEM)
                    654:        {
                    655:          this_struct_value_rtx = force_reg (Pmode, structure_value_addr);
                    656:        }
                    657:       else
                    658:        {
                    659:          this_struct_value_rtx = struct_value_rtx;
                    660:          emit_move_insn (this_struct_value_rtx, structure_value_addr);
                    661:        }
                    662:     }
1.1       root      663: 
                    664:   /* Now prepare for copying the insns.
                    665:      Set up reg_map, parm_map and label_map saying how to translate
                    666:      the pseudo-registers, stack-parm references and labels when copying.  */
                    667: 
                    668:   reg_map = (rtx *) alloca (max_regno * sizeof (rtx));
                    669:   bzero (reg_map, max_regno * sizeof (rtx));
                    670: 
                    671:   if (DECL_ARGUMENTS (fndecl))
                    672:     {
                    673:       tree decl = DECL_ARGUMENTS (fndecl);
                    674:       int offset = FUNCTION_ARGS_SIZE (header);
1.1.1.7   root      675: 
1.1       root      676:       parm_map =
                    677:        (rtx *)alloca ((offset / UNITS_PER_WORD) * sizeof (rtx));
                    678:       bzero (parm_map, (offset / UNITS_PER_WORD) * sizeof (rtx));
1.1.1.7   root      679:       parm_map -= first_parm_offset / UNITS_PER_WORD;
1.1       root      680: 
                    681:       for (formal = decl, i = 0; formal; formal = TREE_CHAIN (formal), i++)
                    682:        {
                    683:          /* Create an entry in PARM_MAP that says what pseudo register
                    684:             is associated with an address we might compute.  */
1.1.1.7   root      685:          if (DECL_OFFSET (formal) >= 0)
                    686:            {
                    687:              /* This parameter has a home in the stack.  */
                    688:              parm_map[DECL_OFFSET (formal) / BITS_PER_WORD] = arg_vec[i];
                    689:            }
                    690:          else
                    691:            {
                    692:              /* Parameter that was passed in a register;
                    693:                 does it have a home on the stack (as a local)?  */
                    694:              rtx frtx = DECL_RTL (formal);
                    695:              rtx offset = 0;
                    696:              if (GET_CODE (frtx) == MEM)
                    697:                {
                    698:                  frtx = XEXP (frtx, 0);
                    699:                  if (GET_CODE (frtx) == PLUS)
                    700:                    {
                    701:                      if (XEXP (frtx, 0) == frame_pointer_rtx
                    702:                          && GET_CODE (XEXP (frtx, 1)) == CONST_INT)
                    703:                        offset = XEXP (frtx, 1);
                    704:                      else if (XEXP (frtx, 1) == frame_pointer_rtx
                    705:                               && GET_CODE (XEXP (frtx, 0)) == CONST_INT)
                    706:                        offset = XEXP (frtx, 0);
                    707:                    }
                    708:                  if (offset)
                    709:                    parm_map[INTVAL (offset) / UNITS_PER_WORD] = arg_vec[i];
                    710:                  else abort ();
                    711:                }
                    712:              else if (GET_CODE (frtx) != REG)
                    713:                abort ();
                    714:            }
1.1       root      715:          /* Create an entry in REG_MAP that says what rtx is associated
                    716:             with a pseudo register from the function being inlined.  */
                    717:          if (GET_CODE (DECL_RTL (formal)) == REG)
                    718:            reg_map[REGNO (DECL_RTL (formal))] = arg_vec[i];
                    719:        }
1.1.1.7   root      720: 
1.1.1.8   root      721:       /* Make certain that we can accept struct_value_{incoming_rtx,rtx},
1.1.1.7   root      722:         and map it.  If it is a hard register, it is mapped automagically.  */
                    723:       if (GET_CODE (struct_value_incoming_rtx) == REG)
                    724:        ;
                    725:       else if (GET_CODE (struct_value_incoming_rtx) == MEM
                    726:               && XEXP (XEXP (struct_value_incoming_rtx, 0), 0) == frame_pointer_rtx
                    727:               && GET_CODE (XEXP (XEXP (struct_value_incoming_rtx, 0), 1)) == CONST_INT)
                    728:        parm_map[INTVAL (XEXP (XEXP (struct_value_incoming_rtx, 0), 1)) / UNITS_PER_WORD]
                    729:          = this_struct_value_rtx;
                    730:       else
                    731:        abort ();
1.1       root      732:     }
                    733:   else
                    734:     {
                    735:       parm_map = NULL;
                    736:     }
                    737: 
                    738:   label_map = (rtx *)alloca ((max_labelno - min_labelno) * sizeof (rtx));
                    739:   label_map -= min_labelno;
                    740: 
                    741:   for (i = min_labelno; i < max_labelno; i++)
                    742:     label_map[i] = gen_label_rtx ();
                    743: 
1.1.1.6   root      744:   /* As we copy insns, record the correspondence, so that inter-insn
                    745:      references can be copied into isomorphic structure.  */
                    746: 
                    747:   insn_map = (rtx *) alloca (INSN_UID (header) * sizeof (rtx));
                    748:   bzero (insn_map, INSN_UID (header) * sizeof (rtx));
                    749: 
1.1       root      750:   /* Set up a target to translate the inline function's value-register.  */
                    751: 
                    752:   if (structure_value_addr != 0 || TYPE_MODE (type) == VOIDmode)
                    753:     inline_target = 0;
                    754:   else
1.1.1.3   root      755:     {
                    756:       /* Machine mode function was declared to return.   */
                    757:       enum machine_mode departing_mode = TYPE_MODE (type);
                    758:       /* (Possibly wider) machine mode it actually computes
                    759:         (for the sake of callers that fail to declare it right).  */
                    760:       enum machine_mode arriving_mode
1.1.1.10  root      761:        = TYPE_MODE (DECL_RESULT_TYPE (fndecl));
1.1.1.3   root      762: 
1.1.1.5   root      763:       /* Don't use MEMs as direct targets because on some machines
                    764:         substituting a MEM for a REG makes invalid insns.
                    765:         Let the combiner substitute the MEM if that is valid.  */
                    766:       if (target && GET_CODE (target) == REG
                    767:          && GET_MODE (target) == departing_mode)
1.1.1.3   root      768:        inline_target = target;
                    769:       else
                    770:        inline_target = target = gen_reg_rtx (departing_mode);
                    771: 
                    772:       /* If function's value was promoted before return,
                    773:         avoid machine mode mismatch when we substitute INLINE_TARGET.
                    774:         But TARGET is what we will return to the caller.  */
                    775:       if (arriving_mode != departing_mode)
                    776:        inline_target = gen_rtx (SUBREG, arriving_mode, target, 0);
                    777:     }
1.1       root      778: 
                    779:   /* We are about to make space in this function's stack frame
                    780:      for a copy of the stack frame of the inline function.
                    781:      First, create an RTX that points to that stack frame
                    782:      with the same offset usually used for the frame pointer.
                    783:      This will be substituted for all frame-pointer references.  */
                    784: 
                    785:   fp_delta = get_frame_size ();
                    786: #ifdef FRAME_GROWS_DOWNWARD
                    787:   fp_delta = - fp_delta;
                    788: #endif
                    789:   fp_delta -= STARTING_FRAME_OFFSET;
                    790: 
                    791:   inline_fp_rtx
                    792:     = copy_to_mode_reg (Pmode,
                    793:                        plus_constant (frame_pointer_rtx, fp_delta));
                    794: 
                    795:   /* Now allocate the space for that to point at.  */
                    796: 
                    797:   assign_stack_local (VOIDmode, DECL_FRAME_SIZE (fndecl));
                    798: 
                    799:   /* Now copy the insns one by one.  */
                    800: 
                    801:   for (insn = insns; insn; insn = NEXT_INSN (insn))
                    802:     {
                    803:       rtx copy, pattern, next = 0;
                    804: 
1.1.1.11! root      805:       orig_asm_operands_vector = 0;
        !           806:       copy_asm_operands_vector = 0;
        !           807: 
1.1       root      808:       switch (GET_CODE (insn))
                    809:        {
                    810:        case INSN:
                    811:          pattern = PATTERN (insn);
                    812: 
                    813:          /* Special handling for the insn immediately after a CALL_INSN
                    814:             that returned a value:
                    815:             If it does copy the value, we must avoid the usual translation
                    816:             of the return-register into INLINE_TARGET.
                    817:             If it just USEs the value, the inline function expects it to
                    818:             stay in the return-register and be returned,
                    819:             so copy it into INLINE_TARGET.  */
                    820: 
                    821:          if (follows_call
                    822:              /* Allow a stack-adjust, handled normally, to come in between
                    823:                 the call and the value-copying insn.  */
                    824:              && ! (GET_CODE (pattern) == SET
                    825:                    && SET_DEST (pattern) == stack_pointer_rtx))
                    826:            {
                    827:              if (GET_CODE (pattern) == SET
                    828:                  && rtx_equal_p (SET_SRC (pattern), follows_call))
                    829:                /* This insn copies the value: take special care to copy
                    830:                   that value to this insn's destination.  */
                    831:                {
                    832:                  copy = emit_insn (gen_rtx (SET, VOIDmode,
                    833:                                             copy_rtx_and_substitute (SET_DEST (pattern)),
                    834:                                             follows_call));
1.1.1.9   root      835:                  RTX_INTEGRATED_P (copy) = 1;
1.1       root      836:                  follows_call = 0;
                    837:                  break;
                    838:                }
                    839:              else if (GET_CODE (pattern) == USE
                    840:                       && rtx_equal_p (XEXP (pattern, 0), follows_call))
                    841:                /* This insn does nothing but says the value is expected
                    842:                   to flow through to the inline function's return-value.
                    843:                   Make that happen, then ignore this insn.  */
                    844:                {
                    845:                  copy = emit_insn (gen_rtx (SET, VOIDmode, inline_target,
                    846:                                             follows_call));
1.1.1.9   root      847:                  RTX_INTEGRATED_P (copy) = 1;
1.1       root      848:                  follows_call = 0;
                    849:                  break;
                    850:                }
                    851:              /* If it does neither, this value must be ignored.  */
                    852:              follows_call = 0;
                    853:            }
                    854: 
                    855:          /* The (USE (REG n)) at return from the function should be ignored
                    856:             since we are changing (REG n) into inline_target.  */
1.1.1.6   root      857:          copy = 0;
1.1       root      858:          if (GET_CODE (pattern) == USE
                    859:              && GET_CODE (XEXP (pattern, 0)) == REG
1.1.1.5   root      860:              && REG_FUNCTION_VALUE_P (XEXP (pattern, 0)))
1.1       root      861:            break;
                    862: 
                    863:          /* Try to do some quick constant folding here.
                    864:             This will save save execution time of the compiler,
                    865:             as well time and space of the program if done here.  */
                    866:          if (GET_CODE (pattern) == SET
                    867:              && SET_DEST (pattern) == cc0_rtx)
                    868:            next = try_fold_cc0 (insn);
                    869: 
                    870:          if (next != 0)
                    871:            {
                    872:              insn = next;
                    873:            }
                    874:          else
                    875:            {
                    876:              copy = emit_insn (copy_rtx_and_substitute (pattern));
1.1.1.9   root      877:              RTX_INTEGRATED_P (copy) = 1;
1.1       root      878:            }
                    879:          break;
                    880: 
                    881:        case JUMP_INSN:
                    882:          follows_call = 0;
                    883:          if (GET_CODE (PATTERN (insn)) == RETURN)
                    884:            {
1.1.1.9   root      885:              if (local_return_label == 0)
                    886:                local_return_label = gen_label_rtx ();
                    887:              emit_jump (local_return_label);
1.1       root      888:              break;
                    889:            }
                    890:          copy = emit_jump_insn (copy_rtx_and_substitute (PATTERN (insn)));
1.1.1.9   root      891:          RTX_INTEGRATED_P (copy) = 1;
1.1       root      892:          break;
                    893: 
                    894:        case CALL_INSN:
1.1.1.6   root      895: #if 0
                    896:          /* This should no longer be necessary now that references
                    897:             to this function's return value are flagged to distinguish
                    898:             them from other references to the same hard register.  */
1.1       root      899:          {
                    900:            rtx newbod;
                    901:            /* If the call's body is (set (reg...) (call...)),
                    902:               the register is a function return register, but DON'T
                    903:               translate it into INLINE_TARGET because it describes the
                    904:               called function, not the caller's return value.  */
                    905:            if (GET_CODE (PATTERN (insn)) == SET)
                    906:              newbod = gen_rtx (SET, VOIDmode, SET_DEST (PATTERN (insn)),
                    907:                                copy_rtx_and_substitute (SET_SRC (PATTERN (insn))));
1.1.1.6   root      908:            else if (GET_CODE (PATTERN (insn)) == PARALLEL
                    909:                     && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET)
                    910:              {
                    911:                register int j;
                    912:                rtx newelem;
                    913:                newbod = gen_rtx (PARALLEL, VOIDmode,
                    914:                                  rtvec_alloc (XVECLEN (PATTERN (insn), 0)));
                    915:                newelem = gen_rtx (SET, VOIDmode,
                    916:                                   SET_DEST (XVECEXP (PATTERN (insn), 0, 0)),
                    917:                                   copy_rtx_and_substitute (SET_SRC (XVECEXP (PATTERN (insn), 0, 0))));
                    918:                XVECEXP (newbod, 0, 0) = newelem;
                    919:                for (j = 1; j < XVECLEN (newbod, 0); j++)
                    920:                  XVECEXP (newbod, 0, j)
                    921:                    = copy_rtx_and_substitute (XVECEXP (PATTERN (insn), 0, j));
                    922:              }
1.1       root      923:            else
                    924:              newbod = copy_rtx_and_substitute (PATTERN (insn));
                    925:            copy = emit_call_insn (newbod);
                    926:          }
1.1.1.6   root      927: #else /* 1 */
                    928:          copy = emit_call_insn (copy_rtx_and_substitute (PATTERN (insn)));
                    929: #endif /* 1 */
1.1.1.9   root      930:          RTX_INTEGRATED_P (copy) = 1;
1.1       root      931:          /* Special handling needed for the following INSN depending on
                    932:             whether it copies the value from the fcn return reg.  */
                    933:          if (GET_CODE (PATTERN (insn)) == SET)
                    934:            follows_call = SET_DEST (PATTERN (insn));
                    935:          break;
                    936: 
                    937:        case CODE_LABEL:
1.1.1.6   root      938:          copy = emit_label (label_map[CODE_LABEL_NUMBER (insn)]);
1.1       root      939:          follows_call = 0;
                    940:          break;
                    941: 
                    942:        case BARRIER:
1.1.1.6   root      943:          copy = emit_barrier ();
1.1       root      944:          break;
                    945: 
                    946:        case NOTE:
1.1.1.7   root      947:          if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END)
                    948:            copy = emit_note (NOTE_SOURCE_FILE (insn), NOTE_LINE_NUMBER (insn));
                    949:          else
                    950:            copy = 0;
1.1       root      951:          break;
                    952: 
                    953:        default:
                    954:          abort ();
                    955:          break;
                    956:        }
1.1.1.6   root      957: 
                    958:       insn_map[INSN_UID (insn)] = copy;
1.1       root      959:     }
                    960: 
1.1.1.9   root      961:   if (local_return_label)
                    962:     emit_label (local_return_label);
1.1       root      963: 
                    964:   /* Make copies of the decls of the symbols in the inline function, so that
                    965:      the copies of the variables get declared in the current function.  */
                    966:   copy_decl_tree (DECL_INITIAL (fndecl), 0);
                    967: 
                    968:   /* End the scope containing the copied formal parameter variables.  */
                    969: 
1.1.1.10  root      970:   expand_end_bindings (getdecls (), 1, 1);
1.1       root      971:   poplevel (1, 1, 0);
                    972: 
                    973:   reg_map = NULL;
                    974:   label_map = NULL;
                    975: 
                    976:   if (ignore || TYPE_MODE (type) == VOIDmode)
                    977:     return 0;
                    978: 
                    979:   if (structure_value_addr)
                    980:     {
                    981:       if (target)
                    982:        return target;
                    983:       return gen_rtx (MEM, BLKmode,
                    984:                      memory_address (BLKmode, structure_value_addr));
                    985:     }
                    986: 
1.1.1.3   root      987:   return target;
1.1       root      988: }
                    989: 
                    990: /* Given a chain of PARM_DECLs, ARGS, and a vector of RTL homes VEC,
                    991:    copy each decl into a VAR_DECL, push all of those decls
                    992:    and give each one the corresponding home.  */
                    993: 
                    994: static void
                    995: copy_parm_decls (args, vec)
                    996:      tree args;
                    997:      rtx *vec;
                    998: {
                    999:   register tree tail;
                   1000:   register int i;
                   1001: 
                   1002:   for (tail = args, i = 0; tail; tail = TREE_CHAIN (tail), i++)
                   1003:     {
                   1004:       register tree decl = pushdecl (build_decl (VAR_DECL, DECL_NAME (tail),
                   1005:                                                 TREE_TYPE (tail)));
1.1.1.9   root     1006:       /* These args would always appear unused, if not for this.  */
                   1007:       TREE_USED (decl) = 1;
1.1       root     1008:       DECL_RTL (decl) = vec[i];
                   1009:     }
                   1010: }
                   1011: 
                   1012: /* Given a LET_STMT node, push decls and levels
                   1013:    so as to construct in the current function a tree of contexts
                   1014:    isomorphic to the one that is given.  */
                   1015: 
                   1016: static void
                   1017: copy_decl_tree (let, level)
                   1018:      tree let;
                   1019:      int level;
                   1020: {
                   1021:   tree t;
                   1022: 
                   1023:   pushlevel (0);
                   1024:   
                   1025:   for (t = STMT_VARS (let); t; t = TREE_CHAIN (t))
                   1026:     {
                   1027:       tree d = build_decl (TREE_CODE (t), DECL_NAME (t), TREE_TYPE (t));
                   1028:       DECL_SOURCE_LINE (d) = DECL_SOURCE_LINE (t);
                   1029:       DECL_SOURCE_FILE (d) = DECL_SOURCE_FILE (t);
                   1030:       if (DECL_RTL (t) != 0)
1.1.1.8   root     1031:        {
                   1032:          if (GET_CODE (DECL_RTL (t)) == MEM
                   1033:              && CONSTANT_ADDRESS_P (XEXP (DECL_RTL (t), 0)))
                   1034:            /* copy_rtx_and_substitute would call memory_address
                   1035:               which would copy the address into a register.
                   1036:               Then debugging-output wouldn't know how to handle it.  */
                   1037:            DECL_RTL (d) = DECL_RTL (t);
                   1038:          else
                   1039:            DECL_RTL (d) = copy_rtx_and_substitute (DECL_RTL (t));
                   1040:        }
1.1       root     1041:       TREE_EXTERNAL (d) = TREE_EXTERNAL (t);
                   1042:       TREE_STATIC (d) = TREE_STATIC (t);
                   1043:       TREE_PUBLIC (d) = TREE_PUBLIC (t);
                   1044:       TREE_LITERAL (d) = TREE_LITERAL (t);
                   1045:       TREE_ADDRESSABLE (d) = TREE_ADDRESSABLE (t);
                   1046:       TREE_READONLY (d) = TREE_READONLY (t);
                   1047:       TREE_VOLATILE (d) = TREE_VOLATILE (t);
1.1.1.9   root     1048:       /* These args would always appear unused, if not for this.  */
                   1049:       TREE_USED (d) = 1;
1.1       root     1050:       pushdecl (d);
                   1051:     }
                   1052: 
                   1053:   for (t = STMT_BODY (let); t; t = TREE_CHAIN (t))
                   1054:     copy_decl_tree (t, level + 1);
                   1055: 
                   1056:   poplevel (level > 0, 0, 0);
                   1057: }
                   1058: 
                   1059: /* Create a new copy of an rtx.
                   1060:    Recursively copies the operands of the rtx,
                   1061:    except for those few rtx codes that are sharable.  */
                   1062: 
                   1063: static rtx
                   1064: copy_rtx_and_substitute (orig)
                   1065:      register rtx orig;
                   1066: {
                   1067:   register rtx copy, temp;
                   1068:   register int i, j;
                   1069:   register RTX_CODE code;
                   1070:   register enum machine_mode mode;
                   1071:   register char *format_ptr;
                   1072:   int regno;
                   1073: 
                   1074:   if (orig == 0)
                   1075:     return 0;
                   1076: 
                   1077:   code = GET_CODE (orig);
                   1078:   mode = GET_MODE (orig);
                   1079: 
                   1080:   switch (code)
                   1081:     {
                   1082:     case REG:
                   1083:       /* If a frame-pointer register shows up, then we
                   1084:         must `fix' the reference.  If the stack pointer
                   1085:         register shows up, it must be part of stack-adjustments
                   1086:         (*not* because we eliminated the frame pointer!).
                   1087:         Small hard registers are returned as-is.  Pseudo-registers
                   1088:         go through their `reg_map'.  */
                   1089:       regno = REGNO (orig);
                   1090:       if (regno < FIRST_PSEUDO_REGISTER)
                   1091:        {
1.1.1.5   root     1092:          if (REG_FUNCTION_VALUE_P (orig))
1.1.1.9   root     1093:            {
                   1094:              /* This is a reference to the function return value.  If
                   1095:                 the function doesn't have a return value, error.
                   1096:                 If it does, it may not be the same mode as `inline_target'
                   1097:                 because SUBREG is not required for hard regs.
                   1098:                 If not, adjust mode of inline_target to fit the context.  */
                   1099:              if (inline_target == 0)
                   1100:                abort ();
                   1101:              if (mode == GET_MODE (inline_target))
                   1102:                return inline_target;
                   1103:              return gen_rtx (SUBREG, mode, inline_target, 0);
                   1104:            }
1.1       root     1105:          if (regno == FRAME_POINTER_REGNUM)
                   1106:            return plus_constant (orig, fp_delta);
                   1107:          return orig;
                   1108:        }
                   1109:       if (reg_map[regno] == NULL)
                   1110:        reg_map[regno] = gen_reg_rtx (mode);
                   1111:       return reg_map[regno];
                   1112: 
                   1113:     case CODE_LABEL:
                   1114:       return label_map[CODE_LABEL_NUMBER (orig)];
                   1115: 
                   1116:     case LABEL_REF:
                   1117:       copy = rtx_alloc (LABEL_REF);
                   1118:       PUT_MODE (copy, mode);
                   1119:       XEXP (copy, 0) = label_map[CODE_LABEL_NUMBER (XEXP (orig, 0))];
                   1120:       return copy;
                   1121: 
                   1122:     case PC:
                   1123:     case CC0:
                   1124:     case CONST_INT:
                   1125:     case CONST_DOUBLE:
                   1126:     case SYMBOL_REF:
                   1127:       return orig;
                   1128: 
1.1.1.11! root     1129:     case ASM_OPERANDS:
        !          1130:       /* If a single asm insn contains multiple output operands
        !          1131:         then it contains multiple ASM_OPERANDS rtx's that share operand 3.
        !          1132:         We must make sure that the copied insn continues to share it.  */
        !          1133:       if (orig_asm_operands_vector == XVEC (orig, 3))
        !          1134:        {
        !          1135:          copy = rtx_alloc (ASM_OPERANDS);
        !          1136:          XSTR (copy, 0) = XSTR (orig, 0);
        !          1137:          XSTR (copy, 1) = XSTR (orig, 1);
        !          1138:          XINT (copy, 2) = XINT (orig, 2);
        !          1139:          XVEC (copy, 3) = copy_asm_operands_vector;
        !          1140:          XVEC (copy, 4) = XVEC (orig, 4);
        !          1141:          return copy;
        !          1142:        }
        !          1143:       break;
        !          1144: 
1.1.1.5   root     1145:     case CALL:
                   1146:       /* This is given special treatment because the first
                   1147:         operand of a CALL is a (MEM ...) which may get
                   1148:         forced into a register for cse.  This is undesirable
                   1149:         if function-address cse isn't wanted or if we won't do cse.  */
                   1150: #ifndef NO_FUNCTION_CSE
                   1151:       if (! (optimize && ! flag_no_function_cse))
                   1152: #endif
                   1153:        return gen_rtx (CALL, GET_MODE (orig),
                   1154:                        gen_rtx (MEM, GET_MODE (XEXP (orig, 0)),
                   1155:                                 copy_rtx_and_substitute (XEXP (XEXP (orig, 0), 0))),
                   1156:                        copy_rtx_and_substitute (XEXP (orig, 1)));
                   1157:       break;
                   1158: 
1.1       root     1159:     case PLUS:
                   1160:       /* Note:  the PLUS case is not nearly as careful as the MEM
                   1161:         case in terms of preserving addresses.  The reason for this
                   1162:         is that it is expected that if a PLUS_EXPR turns out not
                   1163:         to be a legitimate address, reload can fix that up, without
                   1164:         doing major damage.  However, a MEM rtx must preside
                   1165:         over a legitimate address.  The MEM case has lots of hair
                   1166:         to deal with what happens when it sits on a PLUS...  */
                   1167:       /* Take care of the easy case quickly.  */
                   1168:       if (XEXP (orig, 0) == frame_pointer_rtx
                   1169:          || XEXP (orig, 1) == frame_pointer_rtx
                   1170:          || (ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
                   1171:              && (XEXP (orig, 0) == arg_pointer_rtx
                   1172:                  || XEXP (orig, 1) == arg_pointer_rtx)))
                   1173:        {
                   1174:          if (XEXP (orig, 0) == frame_pointer_rtx
                   1175:              || XEXP (orig, 0) == arg_pointer_rtx)
                   1176:            copy = XEXP (orig, 1);
                   1177:          else
                   1178:            copy = XEXP (orig, 0);
                   1179: 
                   1180:          if (GET_CODE (copy) == CONST_INT)
                   1181:            {
                   1182:              int c = INTVAL (copy);
                   1183: 
                   1184:              if (c > 0)
                   1185:                {
                   1186:                  copy = parm_map[c / UNITS_PER_WORD];
                   1187:                  return XEXP (copy, 0);
                   1188:                }
                   1189:              return gen_rtx (PLUS, mode,
                   1190:                              frame_pointer_rtx,
                   1191:                              gen_rtx (CONST_INT, SImode,
                   1192:                                       c + fp_delta));
                   1193:            }
                   1194:          copy = copy_rtx_and_substitute (copy);
1.1.1.6   root     1195:          temp = force_reg (mode, gen_rtx (PLUS, mode, frame_pointer_rtx, copy));
1.1       root     1196:          return plus_constant (temp, fp_delta);
                   1197:        }
                   1198:       else if (reg_mentioned_p (frame_pointer_rtx, orig)
                   1199:               || (ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
                   1200:                   && reg_mentioned_p (arg_pointer_rtx, orig)))
                   1201:        {
                   1202:          /* If we have a complex sum which has a frame pointer
                   1203:             in it, and it was a legitimate address, then
                   1204:             keep it that way.  */
                   1205:          if (memory_address_p (mode, orig))
                   1206:            {
                   1207:              if (GET_CODE (XEXP (orig, 0)) == CONST_INT)
                   1208:                {
                   1209:                  copy = copy_rtx_and_substitute (XEXP (orig, 1));
                   1210:                  temp = plus_constant (copy, INTVAL (XEXP (orig, 0)));
                   1211:                }
                   1212:              else if (GET_CODE (XEXP (orig, 1)) == CONST_INT)
                   1213:                {
                   1214:                  copy = copy_rtx_and_substitute (XEXP (orig, 0));
                   1215:                  temp = plus_constant (copy, INTVAL (XEXP (orig, 1)));
                   1216:                }
                   1217:              else
                   1218:                {
                   1219:                  temp = gen_rtx (PLUS, GET_MODE (orig),
                   1220:                                  copy_rtx_and_substitute (XEXP (orig, 0)),
                   1221:                                  copy_rtx_and_substitute (XEXP (orig, 1)));
                   1222:                }
                   1223:              temp = memory_address (mode, temp);
                   1224:            }
                   1225:          else
                   1226:            temp = gen_rtx (PLUS, GET_MODE (orig),
                   1227:                            copy_rtx_and_substitute (XEXP (orig, 0)),
                   1228:                            copy_rtx_and_substitute (XEXP (orig, 1)));
                   1229:        }
                   1230:       else
                   1231:        temp = gen_rtx (PLUS, GET_MODE (orig),
                   1232:                        copy_rtx_and_substitute (XEXP (orig, 0)),
                   1233:                        copy_rtx_and_substitute (XEXP (orig, 1)));
                   1234: 
                   1235:       return temp;
1.1.1.7   root     1236: 
1.1       root     1237:     case MEM:
                   1238:       /* Take care of easiest case here.  */
                   1239:       copy = XEXP (orig, 0);
                   1240:       if (copy == frame_pointer_rtx || copy == arg_pointer_rtx)
                   1241:        return gen_rtx (MEM, mode,
                   1242:                        plus_constant (frame_pointer_rtx, fp_delta));
1.1.1.6   root     1243: 
                   1244:       /* Allow a pushing-address even if that is not valid as an
                   1245:         ordinary memory address.  It indicates we are inlining a special
1.1.1.9   root     1246:         push-insn.  These must be copied; otherwise unshare_all_rtl
                   1247:         might clobber them to point at temporary rtl of this function.  */
1.1.1.6   root     1248: #ifdef STACK_GROWS_DOWNWARD
                   1249:       if (GET_CODE (copy) == PRE_DEC && XEXP (copy, 0) == stack_pointer_rtx)
1.1.1.9   root     1250:        return gen_rtx (MEM, mode, copy_rtx_and_substitute (copy));
1.1.1.6   root     1251: #else
                   1252:       if (GET_CODE (copy) == PRE_INC && XEXP (copy, 0) == stack_pointer_rtx)
1.1.1.9   root     1253:        return gen_rtx (MEM, mode, copy_rtx_and_substitute (copy));
1.1.1.6   root     1254: #endif
                   1255: 
1.1.1.7   root     1256:       /* If this is some other sort of address that isn't generally valid,
                   1257:         break out all the registers referred to.  */
                   1258:       if (! memory_address_p (mode, copy))
                   1259:        return gen_rtx (MEM, mode, copy_address (copy));
                   1260: 
1.1       root     1261:       if (GET_CODE (copy) == PLUS)
                   1262:        {
                   1263:          if (XEXP (copy, 0) == frame_pointer_rtx
                   1264:              || XEXP (copy, 1) == frame_pointer_rtx
                   1265:              || (ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
                   1266:                  && (XEXP (copy, 0) == arg_pointer_rtx
                   1267:                      || XEXP (copy, 1) == arg_pointer_rtx)))
                   1268:            {
                   1269:              rtx reg;
                   1270:              if (XEXP (copy, 0) == frame_pointer_rtx
                   1271:                  || XEXP (copy, 0) == arg_pointer_rtx)
                   1272:                reg = XEXP (copy, 0), copy = XEXP (copy, 1);
                   1273:              else
                   1274:                reg = XEXP (copy, 1), copy = XEXP (copy, 0);
                   1275: 
                   1276:              if (GET_CODE (copy) == CONST_INT)
                   1277:                {
                   1278:                  int c = INTVAL (copy);
                   1279: 
1.1.1.7   root     1280:                  if (reg == arg_pointer_rtx && c >= first_parm_offset)
1.1       root     1281:                    {
1.1.1.10  root     1282:                      int index = c / UNITS_PER_WORD;
                   1283:                      int offset = c % UNITS_PER_WORD;
                   1284: 
                   1285:                      /* If we are referring to the middle of a multiword parm,
                   1286:                         find the beginning of that parm.
                   1287:                         OFFSET gets the offset of the reference from
                   1288:                         the beginning of the parm.  */
                   1289: 
                   1290:                      while (parm_map[index] == 0)
                   1291:                        {
                   1292:                          index--;
                   1293:                          if (index < first_parm_offset / UNITS_PER_WORD)
                   1294:                            /* If this abort happens, it means we need
                   1295:                               to handle "decrementing" INDEX back far
                   1296:                               enough to start looking among the reg parms
                   1297:                               instead of the stack parms.  What a mess!  */
                   1298:                            abort ();
                   1299:                          offset += UNITS_PER_WORD;
                   1300:                        }
                   1301: 
                   1302:                      copy = parm_map[index];
                   1303: 
1.1.1.11! root     1304: #ifdef BYTES_BIG_ENDIAN
1.1.1.10  root     1305:                      /* Subtract from OFFSET the offset of where
                   1306:                         the actual parm value would start.  */
                   1307:                      if (GET_MODE_SIZE (GET_MODE (copy)) < UNITS_PER_WORD)
                   1308:                        offset
                   1309:                          -= (UNITS_PER_WORD
                   1310:                              - GET_MODE_SIZE (GET_MODE (copy)));
                   1311: #endif
1.1       root     1312: 
                   1313:                      /* If the MEM is only some of the bytes in the parm,
1.1.1.10  root     1314:                         effectively perform a SUBREG of the actual parm.  */
                   1315:                      if ((GET_MODE (copy) != mode
                   1316:                           && GET_MODE (copy) != VOIDmode))
                   1317:                        {
1.1.1.11! root     1318:                          if (GET_CODE (copy) == MEM)
        !          1319:                            return change_address (copy, mode,
        !          1320:                                                   plus_constant (XEXP (copy, 0),
        !          1321:                                                                  offset));
        !          1322:                          if (GET_CODE (copy) == REG)
        !          1323:                            {
        !          1324:                              /* Crash if the portion of the arg wanted
        !          1325:                                 is not the least significant.
        !          1326:                                 Functions with refs to other parts of a
        !          1327:                                 parameter should not be inline--
        !          1328:                                 see function_cannot_inline_p. */
        !          1329: #ifdef BYTES_BIG_ENDIAN
        !          1330:                              if (offset + GET_MODE_SIZE (mode)
        !          1331:                                  != GET_MODE_SIZE (GET_MODE (copy)))
        !          1332:                                abort ();
        !          1333: #else
        !          1334:                              if (offset != 0)
        !          1335:                                abort ();
        !          1336: #endif
        !          1337:                              return gen_rtx (SUBREG, mode, copy, 0);
        !          1338:                            }
        !          1339: 
        !          1340:                          abort ();
1.1.1.10  root     1341:                        }
1.1       root     1342:                      return copy;
                   1343:                    }
                   1344:                  temp = gen_rtx (PLUS, Pmode,
                   1345:                                  frame_pointer_rtx,
                   1346:                                  gen_rtx (CONST_INT, SImode,
                   1347:                                           c + fp_delta));
                   1348:                  if (! memory_address_p (Pmode, temp))
                   1349:                    return gen_rtx (MEM, mode, plus_constant (inline_fp_rtx, c));
                   1350:                }
                   1351:              copy =  copy_rtx_and_substitute (copy);
                   1352:              temp = gen_rtx (PLUS, Pmode, frame_pointer_rtx, copy);
                   1353:              temp = plus_constant (temp, fp_delta);
                   1354:              temp = memory_address (Pmode, temp);
                   1355:            }
                   1356:          else if (reg_mentioned_p (frame_pointer_rtx, copy)
                   1357:                   || (ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
                   1358:                       && reg_mentioned_p (arg_pointer_rtx, copy)))
                   1359:            {
                   1360:              if (GET_CODE (XEXP (copy, 0)) == CONST_INT)
                   1361:                {
                   1362:                  temp = copy_rtx_and_substitute (XEXP (copy, 1));
                   1363:                  temp = plus_constant (temp, INTVAL (XEXP (copy, 0)));
                   1364:                }
                   1365:              else if (GET_CODE (XEXP (copy, 1)) == CONST_INT)
                   1366:                {
                   1367:                  temp = copy_rtx_and_substitute (XEXP (copy, 0));
                   1368:                  temp = plus_constant (temp, INTVAL (XEXP (copy, 1)));
                   1369:                }
                   1370:              else
                   1371:                {
                   1372:                  temp = gen_rtx (PLUS, GET_MODE (copy),
                   1373:                                  copy_rtx_and_substitute (XEXP (copy, 0)),
                   1374:                                  copy_rtx_and_substitute (XEXP (copy, 1)));
                   1375:                }
                   1376:            }
                   1377:          else
                   1378:            {
                   1379:              if (GET_CODE (XEXP (copy, 1)) == CONST_INT)
                   1380:                temp = plus_constant (copy_rtx_and_substitute (XEXP (copy, 0)),
                   1381:                                      INTVAL (XEXP (copy, 1)));
                   1382:              else if (GET_CODE (XEXP (copy, 0)) == CONST_INT)
                   1383:                temp = plus_constant (copy_rtx_and_substitute (XEXP (copy, 1)),
                   1384:                                      INTVAL (XEXP (copy, 0)));
                   1385:              else
                   1386:                {
                   1387:                  rtx left = copy_rtx_and_substitute (XEXP (copy, 0));
                   1388:                  rtx right = copy_rtx_and_substitute (XEXP (copy, 1));
                   1389: 
                   1390:                  temp = gen_rtx (PLUS, GET_MODE (copy), left, right);
                   1391:                }
                   1392:            }
                   1393:        }
                   1394:       else
                   1395:        temp = copy_rtx_and_substitute (copy);
                   1396: 
                   1397:       return change_address (orig, mode, temp);
                   1398: 
                   1399:     case RETURN:
                   1400:       abort ();
                   1401:     }
                   1402: 
                   1403:   copy = rtx_alloc (code);
                   1404:   PUT_MODE (copy, mode);
                   1405:   copy->in_struct = orig->in_struct;
                   1406:   copy->volatil = orig->volatil;
                   1407:   copy->unchanging = orig->unchanging;
                   1408: 
                   1409:   format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
                   1410: 
                   1411:   for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
                   1412:     {
                   1413:       switch (*format_ptr++)
                   1414:        {
                   1415:        case '0':
                   1416:          break;
                   1417: 
                   1418:        case 'e':
                   1419:          XEXP (copy, i) = copy_rtx_and_substitute (XEXP (orig, i));
                   1420:          break;
                   1421: 
1.1.1.6   root     1422:        case 'u':
                   1423:          /* Change any references to old-insns to point to the
                   1424:             corresponding copied insns.  */
1.1.1.9   root     1425:          XEXP (copy, i) = insn_map[INSN_UID (XEXP (orig, i))];
                   1426:          break;
1.1.1.6   root     1427: 
1.1       root     1428:        case 'E':
                   1429:          XVEC (copy, i) = XVEC (orig, i);
1.1.1.6   root     1430:          if (XVEC (orig, i) != NULL && XVECLEN (orig, i) != 0)
1.1       root     1431:            {
                   1432:              XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
                   1433:              for (j = 0; j < XVECLEN (copy, i); j++)
                   1434:                XVECEXP (copy, i, j) = copy_rtx_and_substitute (XVECEXP (orig, i, j));
                   1435:            }
                   1436:          break;
                   1437: 
                   1438:        case 'i':
                   1439:          XINT (copy, i) = XINT (orig, i);
                   1440:          break;
                   1441: 
                   1442:        case 's':
                   1443:          XSTR (copy, i) = XSTR (orig, i);
                   1444:          break;
                   1445: 
                   1446:        default:
                   1447:          abort ();
                   1448:        }
                   1449:     }
1.1.1.11! root     1450: 
        !          1451:   if (code == ASM_OPERANDS && orig_asm_operands_vector == 0)
        !          1452:     {
        !          1453:       orig_asm_operands_vector = XVEC (orig, 3);
        !          1454:       copy_asm_operands_vector = XVEC (copy, 3);
        !          1455:     }
        !          1456: 
1.1       root     1457:   return copy;
                   1458: }
                   1459: 
1.1.1.7   root     1460: /* Like copy_rtx_and_substitute but produces different output, suitable
                   1461:    for an ideosyncractic address that isn't memory_address_p.
                   1462:    The output resembles the input except that REGs and MEMs are replaced
                   1463:    with new psuedo registers.  All the "real work" is done in separate
                   1464:    insns which set up the values of these new registers.  */
                   1465: 
                   1466: static rtx
                   1467: copy_address (orig)
                   1468:      register rtx orig;
                   1469: {
1.1.1.9   root     1470:   register rtx copy;
1.1.1.7   root     1471:   register int i, j;
                   1472:   register RTX_CODE code;
                   1473:   register enum machine_mode mode;
                   1474:   register char *format_ptr;
                   1475: 
                   1476:   if (orig == 0)
                   1477:     return 0;
                   1478: 
                   1479:   code = GET_CODE (orig);
                   1480:   mode = GET_MODE (orig);
                   1481: 
                   1482:   switch (code)
                   1483:     {
                   1484:     case REG:
1.1.1.9   root     1485:       if (REGNO (orig) != FRAME_POINTER_REGNUM)
                   1486:        return copy_rtx_and_substitute (orig);
                   1487:       return plus_constant (frame_pointer_rtx, fp_delta);
                   1488: 
                   1489:     case PLUS:
                   1490:       if (GET_CODE (XEXP (orig, 0)) == REG
                   1491:          && REGNO (XEXP (orig, 0)) == FRAME_POINTER_REGNUM)
                   1492:        return plus_constant (orig, fp_delta);
                   1493:       break;
                   1494: 
1.1.1.7   root     1495:     case MEM:
1.1.1.9   root     1496:       return copy_to_reg (copy_rtx_and_substitute (orig));
1.1.1.7   root     1497: 
                   1498:     case CODE_LABEL:
                   1499:     case LABEL_REF:
1.1.1.9   root     1500:       return copy_rtx_and_substitute (orig);
1.1.1.7   root     1501: 
                   1502:     case PC:
                   1503:     case CC0:
                   1504:     case CONST_INT:
                   1505:     case CONST_DOUBLE:
                   1506:     case SYMBOL_REF:
                   1507:       return orig;
                   1508:     }
                   1509: 
                   1510:   copy = rtx_alloc (code);
                   1511:   PUT_MODE (copy, mode);
                   1512:   copy->in_struct = orig->in_struct;
                   1513:   copy->volatil = orig->volatil;
                   1514:   copy->unchanging = orig->unchanging;
                   1515: 
                   1516:   format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
                   1517: 
                   1518:   for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
                   1519:     {
                   1520:       switch (*format_ptr++)
                   1521:        {
                   1522:        case '0':
                   1523:          break;
                   1524: 
                   1525:        case 'e':
                   1526:          XEXP (copy, i) = copy_rtx_and_substitute (XEXP (orig, i));
                   1527:          break;
                   1528: 
                   1529:        case 'u':
                   1530:          /* Change any references to old-insns to point to the
                   1531:             corresponding copied insns.  */
1.1.1.9   root     1532:          XEXP (copy, i) = insn_map[INSN_UID (XEXP (orig, i))];
                   1533:          break;
1.1.1.7   root     1534: 
                   1535:        case 'E':
                   1536:          XVEC (copy, i) = XVEC (orig, i);
                   1537:          if (XVEC (orig, i) != NULL && XVECLEN (orig, i) != 0)
                   1538:            {
                   1539:              XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
                   1540:              for (j = 0; j < XVECLEN (copy, i); j++)
                   1541:                XVECEXP (copy, i, j) = copy_rtx_and_substitute (XVECEXP (orig, i, j));
                   1542:            }
                   1543:          break;
                   1544: 
                   1545:        case 'i':
                   1546:          XINT (copy, i) = XINT (orig, i);
                   1547:          break;
                   1548: 
                   1549:        case 's':
                   1550:          XSTR (copy, i) = XSTR (orig, i);
                   1551:          break;
                   1552: 
                   1553:        default:
                   1554:          abort ();
                   1555:        }
                   1556:     }
                   1557:   return copy;
                   1558: }
                   1559: 
1.1       root     1560: /* Attempt to simplify INSN while copying it from an inline fn,
                   1561:    assuming it is a SET that sets CC0.
                   1562: 
                   1563:    If we simplify it, we emit the appropriate insns and return
                   1564:    the last insn that we have handled (since we may handle the insn
                   1565:    that follows INSN as well as INSN itself).
                   1566: 
                   1567:    Otherwise we do nothing and return zero.  */
                   1568: 
                   1569: static rtx
                   1570: try_fold_cc0 (insn)
                   1571:      rtx insn;
                   1572: {
                   1573:   rtx cnst = copy_rtx_and_substitute (SET_SRC (PATTERN (insn)));
                   1574:   rtx pat, copy;
                   1575: 
                   1576:   if (CONSTANT_P (cnst)
                   1577:       /* @@ Cautious: Don't know how many of these tests we need.  */
                   1578:       && NEXT_INSN (insn)
                   1579:       && GET_CODE (pat = PATTERN (NEXT_INSN (insn))) == SET
                   1580:       && SET_DEST (pat) == pc_rtx
                   1581:       && GET_CODE (pat = SET_SRC (pat)) == IF_THEN_ELSE
                   1582:       && GET_RTX_LENGTH (GET_CODE (XEXP (pat, 0))) == 2)
                   1583:     {
                   1584:       rtx cnst2;
                   1585:       rtx cond = XEXP (pat, 0);
                   1586: 
                   1587:       if ((XEXP (cond, 0) == cc0_rtx
                   1588:           && CONSTANT_P (XEXP (cond, 1))
                   1589:           && (cnst2 = XEXP (cond, 1)))
                   1590:          || (XEXP (cond, 1) == cc0_rtx
                   1591:              && CONSTANT_P (XEXP (cond, 0))
                   1592:              && (cnst2 = XEXP (cond, 0))))
                   1593:        {
                   1594:          copy = fold_out_const_cc0 (cond, XEXP (pat, 1), XEXP (pat, 2),
                   1595:                                     cnst, cnst2);
                   1596:          if (copy)
                   1597:            {
                   1598:              if (GET_CODE (copy) == LABEL_REF)
                   1599:                {
                   1600:                  /* We will branch unconditionally to
                   1601:                     the label specified by COPY.
                   1602:                     Eliminate dead code by running down the
                   1603:                     list of insn until we see a CODE_LABEL.
                   1604:                     If the CODE_LABEL is the one specified
                   1605:                     by COPY, we win, and can delete all code
                   1606:                     up to (but not necessarily including)
                   1607:                     that label.  Otherwise only win a little:
                   1608:                     emit the branch insn, and continue expanding.  */
                   1609:                  rtx tmp = NEXT_INSN (insn);
                   1610:                  while (tmp && GET_CODE (tmp) != CODE_LABEL)
                   1611:                    tmp = NEXT_INSN (tmp);
                   1612:                  if (! tmp)
                   1613:                    abort ();
                   1614:                  if (label_map[CODE_LABEL_NUMBER (tmp)] == XEXP (copy, 0))
                   1615:                    {
                   1616:                      /* Big win.  */
                   1617:                      return PREV_INSN (tmp);
                   1618:                    }
                   1619:                  else
                   1620:                    {
                   1621:                      /* Small win.  Emit the unconditional branch,
                   1622:                         followed by a BARRIER, so that jump optimization
                   1623:                         will know what to do.  */
                   1624:                      emit_jump (copy);
                   1625:                      return NEXT_INSN (insn);
                   1626:                    }
                   1627:                }
                   1628:              else if (copy == pc_rtx)
                   1629:                {
                   1630:                  /* Do not take the branch, just fall through.
                   1631:                     Jump optimize should handle the elimination of
                   1632:                     dead code if appropriate.  */
                   1633:                  return NEXT_INSN (insn);
                   1634:                }
                   1635:              else
                   1636:                abort ();
                   1637:            }
                   1638:        }
                   1639:     }
                   1640:   return 0;
                   1641: }
                   1642: 
                   1643: /* If (COND_RTX CNST1 CNST2) yield a result we can treat
                   1644:    as being constant, return THEN_RTX if the result is always
                   1645:    non-zero, and return ELSE_RTX otherwise.  */
                   1646: static rtx
                   1647: fold_out_const_cc0 (cond_rtx, then_rtx, else_rtx, cnst1, cnst2)
                   1648:      rtx cond_rtx, then_rtx, else_rtx;
                   1649:      rtx cnst1, cnst2;
                   1650: {
                   1651:   int value1, value2;
                   1652:   int int1 = GET_CODE (cnst1) == CONST_INT;
                   1653:   int int2 = GET_CODE (cnst2) == CONST_INT;
                   1654:   if (int1)
                   1655:     value1 = INTVAL (cnst1);
                   1656:   else
                   1657:     value1 = 1;
                   1658:   if (int2)
                   1659:     value2 = INTVAL (cnst2);
                   1660:   else
                   1661:     value2 = 1;
                   1662: 
                   1663:   switch (GET_CODE (cond_rtx))
                   1664:     {
                   1665:     case NE:
                   1666:       if (int1 && int2)
                   1667:        if (value1 != value2)
                   1668:          return copy_rtx_and_substitute (then_rtx);
                   1669:        else
                   1670:          return copy_rtx_and_substitute (else_rtx);
                   1671:       if (value1 == 0 || value2 == 0)
                   1672:        return copy_rtx_and_substitute (then_rtx);
                   1673:       if (int1 == 0 && int2 == 0)
                   1674:        if (rtx_equal_p (cnst1, cnst2))
                   1675:          return copy_rtx_and_substitute (else_rtx);
                   1676:       break;
                   1677:     case EQ:
                   1678:       if (int1 && int2)
                   1679:        if (value1 == value2)
                   1680:          return copy_rtx_and_substitute (then_rtx);
                   1681:        else
                   1682:          return copy_rtx_and_substitute (else_rtx);
                   1683:       if (value1 == 0 || value2 == 0)
                   1684:        return copy_rtx_and_substitute (else_rtx);
                   1685:       if (int1 == 0 && int2 == 0)
                   1686:        if (rtx_equal_p (cnst1, cnst2))
                   1687:          return copy_rtx_and_substitute (then_rtx);
                   1688:       break;
                   1689:     case GE:
                   1690:       if (int1 && int2)
                   1691:        if (value1 >= value2)
                   1692:          return copy_rtx_and_substitute (then_rtx);
                   1693:        else
                   1694:          return copy_rtx_and_substitute (else_rtx);
                   1695:       if (value1 == 0)
                   1696:        return copy_rtx_and_substitute (else_rtx);
                   1697:       if (value2 == 0)
                   1698:        return copy_rtx_and_substitute (then_rtx);
                   1699:       break;
                   1700:     case GT:
                   1701:       if (int1 && int2)
                   1702:        if (value1 > value2)
                   1703:          return copy_rtx_and_substitute (then_rtx);
                   1704:        else
                   1705:          return copy_rtx_and_substitute (else_rtx);
                   1706:       if (value1 == 0)
                   1707:        return copy_rtx_and_substitute (else_rtx);
                   1708:       if (value2 == 0)
                   1709:        return copy_rtx_and_substitute (then_rtx);
                   1710:       break;
                   1711:     case LE:
                   1712:       if (int1 && int2)
                   1713:        if (value1 <= value2)
                   1714:          return copy_rtx_and_substitute (then_rtx);
                   1715:        else
                   1716:          return copy_rtx_and_substitute (else_rtx);
                   1717:       if (value1 == 0)
                   1718:        return copy_rtx_and_substitute (then_rtx);
                   1719:       if (value2 == 0)
                   1720:        return copy_rtx_and_substitute (else_rtx);
                   1721:       break;
                   1722:     case LT:
                   1723:       if (int1 && int2)
                   1724:        if (value1 < value2)
                   1725:          return copy_rtx_and_substitute (then_rtx);
                   1726:        else
                   1727:          return copy_rtx_and_substitute (else_rtx);
                   1728:       if (value1 == 0)
                   1729:        return copy_rtx_and_substitute (then_rtx);
                   1730:       if (value2 == 0)
                   1731:        return copy_rtx_and_substitute (else_rtx);
                   1732:       break;
                   1733:     case GEU:
                   1734:       if (int1 && int2)
                   1735:        if ((unsigned)value1 >= (unsigned)value2)
                   1736:          return copy_rtx_and_substitute (then_rtx);
                   1737:        else
                   1738:          return copy_rtx_and_substitute (else_rtx);
                   1739:       if (value1 == 0)
                   1740:        return copy_rtx_and_substitute (else_rtx);
                   1741:       if (value2 == 0)
                   1742:        return copy_rtx_and_substitute (then_rtx);
                   1743:       break;
                   1744:     case GTU:
                   1745:       if (int1 && int2)
                   1746:        if ((unsigned)value1 > (unsigned)value2)
                   1747:          return copy_rtx_and_substitute (then_rtx);
                   1748:        else
                   1749:          return copy_rtx_and_substitute (else_rtx);
                   1750:       if (value1 == 0)
                   1751:        return copy_rtx_and_substitute (else_rtx);
                   1752:       if (value2 == 0)
                   1753:        return copy_rtx_and_substitute (then_rtx);
                   1754:       break;
                   1755:     case LEU:
                   1756:       if (int1 && int2)
                   1757:        if ((unsigned)value1 <= (unsigned)value2)
                   1758:          return copy_rtx_and_substitute (then_rtx);
                   1759:        else
                   1760:          return copy_rtx_and_substitute (else_rtx);
                   1761:       if (value1 == 0)
                   1762:        return copy_rtx_and_substitute (then_rtx);
                   1763:       if (value2 == 0)
                   1764:        return copy_rtx_and_substitute (else_rtx);
                   1765:       break;
                   1766:     case LTU:
                   1767:       if (int1 && int2)
                   1768:        if ((unsigned)value1 < (unsigned)value2)
                   1769:          return copy_rtx_and_substitute (then_rtx);
                   1770:        else
                   1771:          return copy_rtx_and_substitute (else_rtx);
                   1772:       if (value1 == 0)
                   1773:        return copy_rtx_and_substitute (then_rtx);
                   1774:       if (value2 == 0)
                   1775:        return copy_rtx_and_substitute (else_rtx);
                   1776:       break;
                   1777:     }
                   1778:   /* Could not hack it.  */
                   1779:   return 0;
                   1780: }
                   1781: 
                   1782: /* Output the assembly language code for the function FNDECL
                   1783:    from its DECL_SAVED_INSNS.  Used for inline functions that are output
                   1784:    at end of compilation instead of where they came in the source.  */
                   1785: 
                   1786: void
                   1787: output_inline_function (fndecl)
                   1788:      tree fndecl;
                   1789: {
                   1790:   rtx head = DECL_SAVED_INSNS (fndecl);
                   1791:   rtx last;
                   1792: 
                   1793:   temporary_allocation ();
                   1794: 
1.1.1.4   root     1795:   current_function_decl = fndecl;
                   1796: 
1.1       root     1797:   /* This call is only used to initialize global variables.
                   1798:      The rtl code it emits will be discarded below.  */
                   1799:   expand_function_start (fndecl);
                   1800: 
                   1801:   /* Set stack frame size.  */
                   1802:   assign_stack_local (BLKmode, DECL_FRAME_SIZE (fndecl));
                   1803: 
                   1804:   restore_reg_data (FIRST_PARM_INSN (head));
                   1805: 
1.1.1.10  root     1806:   expand_function_end (DECL_SOURCE_FILE (fndecl), DECL_SOURCE_LINE (fndecl));
1.1       root     1807: 
                   1808:   for (last = head; NEXT_INSN (last); last = NEXT_INSN (last))
                   1809:     ;
                   1810: 
                   1811:   set_new_first_and_last_insn (FIRST_PARM_INSN (head), last);
                   1812: 
                   1813:   /* Compile this function all the way down to assembly code.  */
                   1814:   rest_of_compilation (fndecl);
                   1815: 
1.1.1.4   root     1816:   current_function_decl = 0;
                   1817: 
1.1       root     1818:   permanent_allocation ();
                   1819: }

unix.superglobalmegacorp.com

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