Annotation of GNUtools/cc/function.c, revision 1.1

1.1     ! root        1: /* Expands front end tree to back end RTL for GNU C-Compiler
        !             2:    Copyright (C) 1987, 88, 89, 91, 92, 1993 Free Software Foundation, Inc.
        !             3: 
        !             4: This file is part of GNU CC.
        !             5: 
        !             6: GNU CC is free software; you can redistribute it and/or modify
        !             7: it under the terms of the GNU General Public License as published by
        !             8: the Free Software Foundation; either version 2, or (at your option)
        !             9: any later version.
        !            10: 
        !            11: GNU CC is distributed in the hope that it will be useful,
        !            12: but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            14: GNU General Public License for more details.
        !            15: 
        !            16: You should have received a copy of the GNU General Public License
        !            17: along with GNU CC; see the file COPYING.  If not, write to
        !            18: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
        !            19: 
        !            20: 
        !            21: /* This file handles the generation of rtl code from tree structure
        !            22:    at the level of the function as a whole.
        !            23:    It creates the rtl expressions for parameters and auto variables
        !            24:    and has full responsibility for allocating stack slots.
        !            25: 
        !            26:    `expand_function_start' is called at the beginning of a function,
        !            27:    before the function body is parsed, and `expand_function_end' is
        !            28:    called after parsing the body.
        !            29: 
        !            30:    Call `assign_stack_local' to allocate a stack slot for a local variable.
        !            31:    This is usually done during the RTL generation for the function body,
        !            32:    but it can also be done in the reload pass when a pseudo-register does
        !            33:    not get a hard register.
        !            34: 
        !            35:    Call `put_var_into_stack' when you learn, belatedly, that a variable
        !            36:    previously given a pseudo-register must in fact go in the stack.
        !            37:    This function changes the DECL_RTL to be a stack slot instead of a reg
        !            38:    then scans all the RTL instructions so far generated to correct them.  */
        !            39: 
        !            40: #include "config.h"
        !            41: 
        !            42: #include <stdio.h>
        !            43: 
        !            44: #include "rtl.h"
        !            45: #include "tree.h"
        !            46: #include "flags.h"
        !            47: #include "function.h"
        !            48: #include "insn-flags.h"
        !            49: #include "expr.h"
        !            50: #include "insn-codes.h"
        !            51: #include "regs.h"
        !            52: #include "hard-reg-set.h"
        !            53: #include "insn-config.h"
        !            54: #include "recog.h"
        !            55: #include "output.h"
        !            56: #include "basic-block.h"
        !            57: #include "obstack.h"
        !            58: #include "bytecode.h"
        !            59: 
        !            60: /* Some systems use __main in a way incompatible with its use in gcc, in these
        !            61:    cases use the macros NAME__MAIN to give a quoted symbol and SYMBOL__MAIN to
        !            62:    give the same symbol without quotes for an alternative entry point.  You
        !            63:    must define both, or niether. */
        !            64: #ifndef NAME__MAIN
        !            65: #define NAME__MAIN "__main"
        !            66: #define SYMBOL__MAIN __main
        !            67: #endif
        !            68: 
        !            69: /* Round a value to the lowest integer less than it that is a multiple of
        !            70:    the required alignment.  Avoid using division in case the value is
        !            71:    negative.  Assume the alignment is a power of two.  */
        !            72: #define FLOOR_ROUND(VALUE,ALIGN) ((VALUE) & ~((ALIGN) - 1))
        !            73: 
        !            74: /* Similar, but round to the next highest integer that meets the
        !            75:    alignment.  */
        !            76: #define CEIL_ROUND(VALUE,ALIGN)        (((VALUE) + (ALIGN) - 1) & ~((ALIGN)- 1))
        !            77: 
        !            78: /* NEED_SEPARATE_AP means that we cannot derive ap from the value of fp
        !            79:    during rtl generation.  If they are different register numbers, this is
        !            80:    always true.  It may also be true if
        !            81:    FIRST_PARM_OFFSET - STARTING_FRAME_OFFSET is not a constant during rtl
        !            82:    generation.  See fix_lexical_addr for details.  */
        !            83: 
        !            84: #if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
        !            85: #define NEED_SEPARATE_AP
        !            86: #endif
        !            87: 
        !            88: /* Number of bytes of args popped by function being compiled on its return.
        !            89:    Zero if no bytes are to be popped.
        !            90:    May affect compilation of return insn or of function epilogue.  */
        !            91: 
        !            92: int current_function_pops_args;
        !            93: 
        !            94: /* Nonzero if function being compiled needs to be given an address
        !            95:    where the value should be stored.  */
        !            96: 
        !            97: int current_function_returns_struct;
        !            98: 
        !            99: /* Nonzero if function being compiled needs to
        !           100:    return the address of where it has put a structure value.  */
        !           101: 
        !           102: int current_function_returns_pcc_struct;
        !           103: 
        !           104: /* Nonzero if function being compiled needs to be passed a static chain.  */
        !           105: 
        !           106: int current_function_needs_context;
        !           107: 
        !           108: /* Nonzero if function being compiled can call setjmp.  */
        !           109: 
        !           110: int current_function_calls_setjmp;
        !           111: 
        !           112: /* Nonzero if function being compiled can call longjmp.  */
        !           113: 
        !           114: int current_function_calls_longjmp;
        !           115: 
        !           116: /* Nonzero if function being compiled receives nonlocal gotos
        !           117:    from nested functions.  */
        !           118: 
        !           119: int current_function_has_nonlocal_label;
        !           120: 
        !           121: /* Nonzero if function being compiled has nonlocal gotos to parent
        !           122:    function.  */
        !           123: 
        !           124: int current_function_has_nonlocal_goto;
        !           125: 
        !           126: /* Nonzero if function being compiled contains nested functions.  */
        !           127: 
        !           128: int current_function_contains_functions;
        !           129: 
        !           130: /* Nonzero if function being compiled can call alloca,
        !           131:    either as a subroutine or builtin.  */
        !           132: 
        !           133: int current_function_calls_alloca;
        !           134: 
        !           135: /* Nonzero if the current function returns a pointer type */
        !           136: 
        !           137: int current_function_returns_pointer;
        !           138: 
        !           139: /* If some insns can be deferred to the delay slots of the epilogue, the
        !           140:    delay list for them is recorded here.  */
        !           141: 
        !           142: rtx current_function_epilogue_delay_list;
        !           143: 
        !           144: /* If function's args have a fixed size, this is that size, in bytes.
        !           145:    Otherwise, it is -1.
        !           146:    May affect compilation of return insn or of function epilogue.  */
        !           147: 
        !           148: int current_function_args_size;
        !           149: 
        !           150: /* # bytes the prologue should push and pretend that the caller pushed them.
        !           151:    The prologue must do this, but only if parms can be passed in registers.  */
        !           152: 
        !           153: int current_function_pretend_args_size;
        !           154: 
        !           155: /* # of bytes of outgoing arguments required to be pushed by the prologue.
        !           156:    If this is non-zero, it means that ACCUMULATE_OUTGOING_ARGS was defined
        !           157:    and no stack adjusts will be done on function calls.  */
        !           158: 
        !           159: int current_function_outgoing_args_size;
        !           160: 
        !           161: /* This is the offset from the arg pointer to the place where the first
        !           162:    anonymous arg can be found, if there is one.  */
        !           163: 
        !           164: rtx current_function_arg_offset_rtx;
        !           165: 
        !           166: /* Nonzero if current function uses varargs.h or equivalent.
        !           167:    Zero for functions that use stdarg.h.  */
        !           168: 
        !           169: int current_function_varargs;
        !           170: 
        !           171: /* Quantities of various kinds of registers
        !           172:    used for the current function's args.  */
        !           173: 
        !           174: CUMULATIVE_ARGS current_function_args_info;
        !           175: 
        !           176: /* Name of function now being compiled.  */
        !           177: 
        !           178: char *current_function_name;
        !           179: 
        !           180: /* If non-zero, an RTL expression for that location at which the current
        !           181:    function returns its result.  Always equal to
        !           182:    DECL_RTL (DECL_RESULT (current_function_decl)), but provided
        !           183:    independently of the tree structures.  */
        !           184: 
        !           185: rtx current_function_return_rtx;
        !           186: 
        !           187: /* Nonzero if the current function uses the constant pool.  */
        !           188: 
        !           189: int current_function_uses_const_pool;
        !           190: 
        !           191: /* Nonzero if the current function uses pic_offset_table_rtx.  */
        !           192: int current_function_uses_pic_offset_table;
        !           193: 
        !           194: /* The arg pointer hard register, or the pseudo into which it was copied.  */
        !           195: rtx current_function_internal_arg_pointer;
        !           196: 
        !           197: /* The FUNCTION_DECL for an inline function currently being expanded.  */
        !           198: tree inline_function_decl;
        !           199: 
        !           200: /* Number of function calls seen so far in current function.  */
        !           201: 
        !           202: int function_call_count;
        !           203: 
        !           204: /* List (chain of TREE_LIST) of LABEL_DECLs for all nonlocal labels
        !           205:    (labels to which there can be nonlocal gotos from nested functions)
        !           206:    in this function.  */
        !           207: 
        !           208: tree nonlocal_labels;
        !           209: 
        !           210: /* RTX for stack slot that holds the current handler for nonlocal gotos.
        !           211:    Zero when function does not have nonlocal labels.  */
        !           212: 
        !           213: rtx nonlocal_goto_handler_slot;
        !           214: 
        !           215: /* RTX for stack slot that holds the stack pointer value to restore
        !           216:    for a nonlocal goto.
        !           217:    Zero when function does not have nonlocal labels.  */
        !           218: 
        !           219: rtx nonlocal_goto_stack_level;
        !           220: 
        !           221: /* Label that will go on parm cleanup code, if any.
        !           222:    Jumping to this label runs cleanup code for parameters, if
        !           223:    such code must be run.  Following this code is the logical return label.  */
        !           224: 
        !           225: rtx cleanup_label;
        !           226: 
        !           227: /* Label that will go on function epilogue.
        !           228:    Jumping to this label serves as a "return" instruction
        !           229:    on machines which require execution of the epilogue on all returns.  */
        !           230: 
        !           231: rtx return_label;
        !           232: 
        !           233: /* List (chain of EXPR_LISTs) of pseudo-regs of SAVE_EXPRs.
        !           234:    So we can mark them all live at the end of the function, if nonopt.  */
        !           235: rtx save_expr_regs;
        !           236: 
        !           237: /* List (chain of EXPR_LISTs) of all stack slots in this function.
        !           238:    Made for the sake of unshare_all_rtl.  */
        !           239: rtx stack_slot_list;
        !           240: 
        !           241: /* Chain of all RTL_EXPRs that have insns in them.  */
        !           242: tree rtl_expr_chain;
        !           243: 
        !           244: /* Label to jump back to for tail recursion, or 0 if we have
        !           245:    not yet needed one for this function.  */
        !           246: rtx tail_recursion_label;
        !           247: 
        !           248: /* Place after which to insert the tail_recursion_label if we need one.  */
        !           249: rtx tail_recursion_reentry;
        !           250: 
        !           251: /* Location at which to save the argument pointer if it will need to be
        !           252:    referenced.  There are two cases where this is done: if nonlocal gotos
        !           253:    exist, or if vars stored at an offset from the argument pointer will be
        !           254:    needed by inner routines.  */
        !           255: 
        !           256: rtx arg_pointer_save_area;
        !           257: 
        !           258: /* Offset to end of allocated area of stack frame.
        !           259:    If stack grows down, this is the address of the last stack slot allocated.
        !           260:    If stack grows up, this is the address for the next slot.  */
        !           261: int frame_offset;
        !           262: 
        !           263: /* List (chain of TREE_LISTs) of static chains for containing functions.
        !           264:    Each link has a FUNCTION_DECL in the TREE_PURPOSE and a reg rtx
        !           265:    in an RTL_EXPR in the TREE_VALUE.  */
        !           266: static tree context_display;
        !           267: 
        !           268: /* List (chain of TREE_LISTs) of trampolines for nested functions.
        !           269:    The trampoline sets up the static chain and jumps to the function.
        !           270:    We supply the trampoline's address when the function's address is requested.
        !           271: 
        !           272:    Each link has a FUNCTION_DECL in the TREE_PURPOSE and a reg rtx
        !           273:    in an RTL_EXPR in the TREE_VALUE.  */
        !           274: static tree trampoline_list;
        !           275: 
        !           276: /* Insn after which register parms and SAVE_EXPRs are born, if nonopt.  */
        !           277: static rtx parm_birth_insn;
        !           278: 
        !           279: #if 0
        !           280: /* Nonzero if a stack slot has been generated whose address is not
        !           281:    actually valid.  It means that the generated rtl must all be scanned
        !           282:    to detect and correct the invalid addresses where they occur.  */
        !           283: static int invalid_stack_slot;
        !           284: #endif
        !           285: 
        !           286: /* Last insn of those whose job was to put parms into their nominal homes.  */
        !           287: static rtx last_parm_insn;
        !           288: 
        !           289: /* 1 + last pseudo register number used for loading a copy
        !           290:    of a parameter of this function.  */
        !           291: static int max_parm_reg;
        !           292: 
        !           293: /* Vector indexed by REGNO, containing location on stack in which
        !           294:    to put the parm which is nominally in pseudo register REGNO,
        !           295:    if we discover that that parm must go in the stack.  */
        !           296: static rtx *parm_reg_stack_loc;
        !           297: 
        !           298: #if 0  /* Turned off because 0 seems to work just as well.  */
        !           299: /* Cleanup lists are required for binding levels regardless of whether
        !           300:    that binding level has cleanups or not.  This node serves as the
        !           301:    cleanup list whenever an empty list is required.  */
        !           302: static tree empty_cleanup_list;
        !           303: #endif
        !           304: 
        !           305: /* Nonzero once virtual register instantiation has been done.
        !           306:    assign_stack_local uses frame_pointer_rtx when this is nonzero.  */
        !           307: static int virtuals_instantiated;
        !           308: 
        !           309: /* These variables hold pointers to functions to
        !           310:    save and restore machine-specific data,
        !           311:    in push_function_context and pop_function_context.  */
        !           312: void (*save_machine_status) ();
        !           313: void (*restore_machine_status) ();
        !           314: 
        !           315: /* Nonzero if we need to distinguish between the return value of this function
        !           316:    and the return value of a function called by this function.  This helps
        !           317:    integrate.c  */
        !           318: 
        !           319: extern int rtx_equal_function_value_matters;
        !           320: extern tree sequence_rtl_expr;
        !           321: extern tree bc_runtime_type_code ();
        !           322: extern rtx bc_build_calldesc ();
        !           323: extern char *bc_emit_trampoline ();
        !           324: extern char *bc_end_function ();
        !           325: 
        !           326: void fixup_gotos ();
        !           327: 
        !           328: static tree round_down ();
        !           329: static rtx round_trampoline_addr ();
        !           330: static rtx fixup_stack_1 ();
        !           331: static void put_reg_into_stack ();
        !           332: static void fixup_var_refs ();
        !           333: static void fixup_var_refs_insns ();
        !           334: static void fixup_var_refs_1 ();
        !           335: static void optimize_bit_field ();
        !           336: static void instantiate_decls ();
        !           337: static void instantiate_decls_1 ();
        !           338: static void instantiate_decl ();
        !           339: static int instantiate_virtual_regs_1 ();
        !           340: static rtx fixup_memory_subreg ();
        !           341: static rtx walk_fixup_memory_subreg ();
        !           342: 
        !           343: /* In order to evaluate some expressions, such as function calls returning
        !           344:    structures in memory, we need to temporarily allocate stack locations.
        !           345:    We record each allocated temporary in the following structure.
        !           346: 
        !           347:    Associated with each temporary slot is a nesting level.  When we pop up
        !           348:    one level, all temporaries associated with the previous level are freed.
        !           349:    Normally, all temporaries are freed after the execution of the statement
        !           350:    in which they were created.  However, if we are inside a ({...}) grouping,
        !           351:    the result may be in a temporary and hence must be preserved.  If the
        !           352:    result could be in a temporary, we preserve it if we can determine which
        !           353:    one it is in.  If we cannot determine which temporary may contain the
        !           354:    result, all temporaries are preserved.  A temporary is preserved by
        !           355:    pretending it was allocated at the previous nesting level.
        !           356: 
        !           357:    Automatic variables are also assigned temporary slots, at the nesting
        !           358:    level where they are defined.  They are marked a "kept" so that
        !           359:    free_temp_slots will not free them.  */
        !           360: 
        !           361: struct temp_slot
        !           362: {
        !           363:   /* Points to next temporary slot.  */
        !           364:   struct temp_slot *next;
        !           365:   /* The rtx to used to reference the slot. */
        !           366:   rtx slot;
        !           367:   /* The size, in units, of the slot.  */
        !           368:   int size;
        !           369:   /* The value of `sequence_rtl_expr' when this temporary is allocated.  */
        !           370:   tree rtl_expr;
        !           371:   /* Non-zero if this temporary is currently in use.  */
        !           372:   char in_use;
        !           373:   /* Nesting level at which this slot is being used.  */
        !           374:   int level;
        !           375:   /* Non-zero if this should survive a call to free_temp_slots.  */
        !           376:   int keep;
        !           377: };
        !           378: 
        !           379: /* List of all temporaries allocated, both available and in use.  */
        !           380: 
        !           381: struct temp_slot *temp_slots;
        !           382: 
        !           383: /* Current nesting level for temporaries.  */
        !           384: 
        !           385: int temp_slot_level;
        !           386: 
        !           387: /* The FUNCTION_DECL node for the current function.  */
        !           388: static tree this_function_decl;
        !           389: 
        !           390: /* Callinfo pointer for the current function.  */
        !           391: static rtx this_function_callinfo;
        !           392: 
        !           393: /* The label in the bytecode file of this function's actual bytecode.
        !           394:    Not an rtx.  */
        !           395: static char *this_function_bytecode;
        !           396: 
        !           397: /* The call description vector for the current function.  */
        !           398: static rtx this_function_calldesc;
        !           399: 
        !           400: /* Size of the local variables allocated for the current function.  */
        !           401: int local_vars_size;
        !           402: 
        !           403: /* Current depth of the bytecode evaluation stack.  */
        !           404: int stack_depth;
        !           405: 
        !           406: /* Maximum depth of the evaluation stack in this function.  */
        !           407: int max_stack_depth;
        !           408: 
        !           409: /* Current depth in statement expressions.  */
        !           410: static int stmt_expr_depth;
        !           411: 
        !           412: /* Pointer to chain of `struct function' for containing functions.  */
        !           413: struct function *outer_function_chain;
        !           414: 
        !           415: /* Given a function decl for a containing function,
        !           416:    return the `struct function' for it.  */
        !           417: 
        !           418: struct function *
        !           419: find_function_data (decl)
        !           420:      tree decl;
        !           421: {
        !           422:   struct function *p;
        !           423:   for (p = outer_function_chain; p; p = p->next)
        !           424:     if (p->decl == decl)
        !           425:       return p;
        !           426:   abort ();
        !           427: }
        !           428: 
        !           429: /* Save the current context for compilation of a nested function.
        !           430:    This is called from language-specific code.
        !           431:    The caller is responsible for saving any language-specific status,
        !           432:    since this function knows only about language-independent variables.  */
        !           433: 
        !           434: void
        !           435: push_function_context ()
        !           436: {
        !           437:   struct function *p = (struct function *) xmalloc (sizeof (struct function));
        !           438: 
        !           439:   p->next = outer_function_chain;
        !           440:   outer_function_chain = p;
        !           441: 
        !           442:   p->name = current_function_name;
        !           443:   p->decl = current_function_decl;
        !           444:   p->pops_args = current_function_pops_args;
        !           445:   p->returns_struct = current_function_returns_struct;
        !           446:   p->returns_pcc_struct = current_function_returns_pcc_struct;
        !           447:   p->needs_context = current_function_needs_context;
        !           448:   p->calls_setjmp = current_function_calls_setjmp;
        !           449:   p->calls_longjmp = current_function_calls_longjmp;
        !           450:   p->calls_alloca = current_function_calls_alloca;
        !           451:   p->has_nonlocal_label = current_function_has_nonlocal_label;
        !           452:   p->has_nonlocal_goto = current_function_has_nonlocal_goto;
        !           453:   p->args_size = current_function_args_size;
        !           454:   p->pretend_args_size = current_function_pretend_args_size;
        !           455:   p->arg_offset_rtx = current_function_arg_offset_rtx;
        !           456:   p->uses_const_pool = current_function_uses_const_pool;
        !           457:   p->uses_pic_offset_table = current_function_uses_pic_offset_table;
        !           458:   p->internal_arg_pointer = current_function_internal_arg_pointer;
        !           459:   p->max_parm_reg = max_parm_reg;
        !           460:   p->parm_reg_stack_loc = parm_reg_stack_loc;
        !           461:   p->outgoing_args_size = current_function_outgoing_args_size;
        !           462:   p->return_rtx = current_function_return_rtx;
        !           463:   p->nonlocal_goto_handler_slot = nonlocal_goto_handler_slot;
        !           464:   p->nonlocal_goto_stack_level = nonlocal_goto_stack_level;
        !           465:   p->nonlocal_labels = nonlocal_labels;
        !           466:   p->cleanup_label = cleanup_label;
        !           467:   p->return_label = return_label;
        !           468:   p->save_expr_regs = save_expr_regs;
        !           469:   p->stack_slot_list = stack_slot_list;
        !           470:   p->parm_birth_insn = parm_birth_insn;
        !           471:   p->frame_offset = frame_offset;
        !           472:   p->tail_recursion_label = tail_recursion_label;
        !           473:   p->tail_recursion_reentry = tail_recursion_reentry;
        !           474:   p->arg_pointer_save_area = arg_pointer_save_area;
        !           475:   p->rtl_expr_chain = rtl_expr_chain;
        !           476:   p->last_parm_insn = last_parm_insn;
        !           477:   p->context_display = context_display;
        !           478:   p->trampoline_list = trampoline_list;
        !           479:   p->function_call_count = function_call_count;
        !           480:   p->temp_slots = temp_slots;
        !           481:   p->temp_slot_level = temp_slot_level;
        !           482:   p->fixup_var_refs_queue = 0;
        !           483:   p->epilogue_delay_list = current_function_epilogue_delay_list;
        !           484: 
        !           485:   save_tree_status (p);
        !           486:   save_storage_status (p);
        !           487:   save_emit_status (p);
        !           488:   init_emit ();
        !           489:   save_expr_status (p);
        !           490:   save_stmt_status (p);
        !           491:   save_varasm_status (p);
        !           492: 
        !           493:   if (save_machine_status)
        !           494:     (*save_machine_status) (p);
        !           495: }
        !           496: 
        !           497: /* Restore the last saved context, at the end of a nested function.
        !           498:    This function is called from language-specific code.  */
        !           499: 
        !           500: void
        !           501: pop_function_context ()
        !           502: {
        !           503:   struct function *p = outer_function_chain;
        !           504: 
        !           505:   outer_function_chain = p->next;
        !           506: 
        !           507:   current_function_name = p->name;
        !           508:   current_function_decl = p->decl;
        !           509:   current_function_pops_args = p->pops_args;
        !           510:   current_function_returns_struct = p->returns_struct;
        !           511:   current_function_returns_pcc_struct = p->returns_pcc_struct;
        !           512:   current_function_needs_context = p->needs_context;
        !           513:   current_function_calls_setjmp = p->calls_setjmp;
        !           514:   current_function_calls_longjmp = p->calls_longjmp;
        !           515:   current_function_calls_alloca = p->calls_alloca;
        !           516:   current_function_has_nonlocal_label = p->has_nonlocal_label;
        !           517:   current_function_has_nonlocal_goto = p->has_nonlocal_goto;
        !           518:   current_function_contains_functions = 1;
        !           519:   current_function_args_size = p->args_size;
        !           520:   current_function_pretend_args_size = p->pretend_args_size;
        !           521:   current_function_arg_offset_rtx = p->arg_offset_rtx;
        !           522:   current_function_uses_const_pool = p->uses_const_pool;
        !           523:   current_function_uses_pic_offset_table = p->uses_pic_offset_table;
        !           524:   current_function_internal_arg_pointer = p->internal_arg_pointer;
        !           525:   max_parm_reg = p->max_parm_reg;
        !           526:   parm_reg_stack_loc = p->parm_reg_stack_loc;
        !           527:   current_function_outgoing_args_size = p->outgoing_args_size;
        !           528:   current_function_return_rtx = p->return_rtx;
        !           529:   nonlocal_goto_handler_slot = p->nonlocal_goto_handler_slot;
        !           530:   nonlocal_goto_stack_level = p->nonlocal_goto_stack_level;
        !           531:   nonlocal_labels = p->nonlocal_labels;
        !           532:   cleanup_label = p->cleanup_label;
        !           533:   return_label = p->return_label;
        !           534:   save_expr_regs = p->save_expr_regs;
        !           535:   stack_slot_list = p->stack_slot_list;
        !           536:   parm_birth_insn = p->parm_birth_insn;
        !           537:   frame_offset = p->frame_offset;
        !           538:   tail_recursion_label = p->tail_recursion_label;
        !           539:   tail_recursion_reentry = p->tail_recursion_reentry;
        !           540:   arg_pointer_save_area = p->arg_pointer_save_area;
        !           541:   rtl_expr_chain = p->rtl_expr_chain;
        !           542:   last_parm_insn = p->last_parm_insn;
        !           543:   context_display = p->context_display;
        !           544:   trampoline_list = p->trampoline_list;
        !           545:   function_call_count = p->function_call_count;
        !           546:   temp_slots = p->temp_slots;
        !           547:   temp_slot_level = p->temp_slot_level;
        !           548:   current_function_epilogue_delay_list = p->epilogue_delay_list;
        !           549: 
        !           550:   restore_tree_status (p);
        !           551:   restore_storage_status (p);
        !           552:   restore_expr_status (p);
        !           553:   restore_emit_status (p);
        !           554:   restore_stmt_status (p);
        !           555:   restore_varasm_status (p);
        !           556: 
        !           557:   if (restore_machine_status)
        !           558:     (*restore_machine_status) (p);
        !           559: 
        !           560:   /* Finish doing put_var_into_stack for any of our variables
        !           561:      which became addressable during the nested function.  */
        !           562:   {
        !           563:     struct var_refs_queue *queue = p->fixup_var_refs_queue;
        !           564:     for (; queue; queue = queue->next)
        !           565:       fixup_var_refs (queue->modified, queue->promoted_mode, queue->unsignedp);
        !           566:   }
        !           567: 
        !           568:   free (p);
        !           569: 
        !           570:   /* Reset variables that have known state during rtx generation.  */
        !           571:   rtx_equal_function_value_matters = 1;
        !           572:   virtuals_instantiated = 0;
        !           573: }
        !           574: 
        !           575: /* Allocate fixed slots in the stack frame of the current function.  */
        !           576: 
        !           577: /* Return size needed for stack frame based on slots so far allocated.
        !           578:    This size counts from zero.  It is not rounded to STACK_BOUNDARY;
        !           579:    the caller may have to do that.  */
        !           580: 
        !           581: int
        !           582: get_frame_size ()
        !           583: {
        !           584: #ifdef FRAME_GROWS_DOWNWARD
        !           585:   return -frame_offset;
        !           586: #else
        !           587:   return frame_offset;
        !           588: #endif
        !           589: }
        !           590: 
        !           591: /* Allocate a stack slot of SIZE bytes and return a MEM rtx for it
        !           592:    with machine mode MODE.
        !           593:    
        !           594:    ALIGN controls the amount of alignment for the address of the slot:
        !           595:    0 means according to MODE,
        !           596:    -1 means use BIGGEST_ALIGNMENT and round size to multiple of that,
        !           597:    positive specifies alignment boundary in bits.
        !           598: 
        !           599:    We do not round to stack_boundary here.  */
        !           600: 
        !           601: rtx
        !           602: assign_stack_local (mode, size, align)
        !           603:      enum machine_mode mode;
        !           604:      int size;
        !           605:      int align;
        !           606: {
        !           607:   register rtx x, addr;
        !           608:   int bigend_correction = 0;
        !           609:   int alignment;
        !           610: 
        !           611:   if (align == 0)
        !           612:     {
        !           613:       alignment = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
        !           614:       if (mode == BLKmode)
        !           615:        alignment = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
        !           616:     }
        !           617:   else if (align == -1)
        !           618:     {
        !           619:       alignment = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
        !           620:       size = CEIL_ROUND (size, alignment);
        !           621:     }
        !           622:   else
        !           623:     alignment = align / BITS_PER_UNIT;
        !           624: 
        !           625:   /* Round frame offset to that alignment.
        !           626:      We must be careful here, since FRAME_OFFSET might be negative and
        !           627:      division with a negative dividend isn't as well defined as we might
        !           628:      like.  So we instead assume that ALIGNMENT is a power of two and
        !           629:      use logical operations which are unambiguous.  */
        !           630: #ifdef FRAME_GROWS_DOWNWARD
        !           631:   frame_offset = FLOOR_ROUND (frame_offset, alignment);
        !           632: #else
        !           633:   frame_offset = CEIL_ROUND (frame_offset, alignment);
        !           634: #endif
        !           635: 
        !           636:   /* On a big-endian machine, if we are allocating more space than we will use,
        !           637:      use the least significant bytes of those that are allocated.  */
        !           638: #if BYTES_BIG_ENDIAN
        !           639:   if (mode != BLKmode)
        !           640:     bigend_correction = size - GET_MODE_SIZE (mode);
        !           641: #endif
        !           642: 
        !           643: #ifdef FRAME_GROWS_DOWNWARD
        !           644:   frame_offset -= size;
        !           645: #endif
        !           646: 
        !           647:   /* If we have already instantiated virtual registers, return the actual
        !           648:      address relative to the frame pointer.  */
        !           649:   if (virtuals_instantiated)
        !           650:     addr = plus_constant (frame_pointer_rtx,
        !           651:                          (frame_offset + bigend_correction
        !           652:                           + STARTING_FRAME_OFFSET));
        !           653:   else
        !           654:     addr = plus_constant (virtual_stack_vars_rtx,
        !           655:                          frame_offset + bigend_correction);
        !           656: 
        !           657: #ifndef FRAME_GROWS_DOWNWARD
        !           658:   frame_offset += size;
        !           659: #endif
        !           660: 
        !           661:   x = gen_rtx (MEM, mode, addr);
        !           662: 
        !           663:   stack_slot_list = gen_rtx (EXPR_LIST, VOIDmode, x, stack_slot_list);
        !           664: 
        !           665:   return x;
        !           666: }
        !           667: 
        !           668: /* Assign a stack slot in a containing function.
        !           669:    First three arguments are same as in preceding function.
        !           670:    The last argument specifies the function to allocate in.  */
        !           671: 
        !           672: rtx
        !           673: assign_outer_stack_local (mode, size, align, function)
        !           674:      enum machine_mode mode;
        !           675:      int size;
        !           676:      int align;
        !           677:      struct function *function;
        !           678: {
        !           679:   register rtx x, addr;
        !           680:   int bigend_correction = 0;
        !           681:   int alignment;
        !           682: 
        !           683:   /* Allocate in the memory associated with the function in whose frame
        !           684:      we are assigning.  */
        !           685:   push_obstacks (function->function_obstack,
        !           686:                 function->function_maybepermanent_obstack);
        !           687: 
        !           688:   if (align == 0)
        !           689:     {
        !           690:       alignment = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
        !           691:       if (mode == BLKmode)
        !           692:        alignment = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
        !           693:     }
        !           694:   else if (align == -1)
        !           695:     {
        !           696:       alignment = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
        !           697:       size = CEIL_ROUND (size, alignment);
        !           698:     }
        !           699:   else
        !           700:     alignment = align / BITS_PER_UNIT;
        !           701: 
        !           702:   /* Round frame offset to that alignment.  */
        !           703: #ifdef FRAME_GROWS_DOWNWARD
        !           704:   function->frame_offset = FLOOR_ROUND (function->frame_offset, alignment);
        !           705: #else
        !           706:   function->frame_offset = CEIL_ROUND (function->frame_offset, alignment);
        !           707: #endif
        !           708: 
        !           709:   /* On a big-endian machine, if we are allocating more space than we will use,
        !           710:      use the least significant bytes of those that are allocated.  */
        !           711: #if BYTES_BIG_ENDIAN
        !           712:   if (mode != BLKmode)
        !           713:     bigend_correction = size - GET_MODE_SIZE (mode);
        !           714: #endif
        !           715: 
        !           716: #ifdef FRAME_GROWS_DOWNWARD
        !           717:   function->frame_offset -= size;
        !           718: #endif
        !           719:   addr = plus_constant (virtual_stack_vars_rtx,
        !           720:                        function->frame_offset + bigend_correction);
        !           721: #ifndef FRAME_GROWS_DOWNWARD
        !           722:   function->frame_offset += size;
        !           723: #endif
        !           724: 
        !           725:   x = gen_rtx (MEM, mode, addr);
        !           726: 
        !           727:   function->stack_slot_list
        !           728:     = gen_rtx (EXPR_LIST, VOIDmode, x, function->stack_slot_list);
        !           729: 
        !           730:   pop_obstacks ();
        !           731: 
        !           732:   return x;
        !           733: }
        !           734: 
        !           735: /* Allocate a temporary stack slot and record it for possible later
        !           736:    reuse.
        !           737: 
        !           738:    MODE is the machine mode to be given to the returned rtx.
        !           739: 
        !           740:    SIZE is the size in units of the space required.  We do no rounding here
        !           741:    since assign_stack_local will do any required rounding.
        !           742: 
        !           743:    KEEP is non-zero if this slot is to be retained after a call to
        !           744:    free_temp_slots.  Automatic variables for a block are allocated with this
        !           745:    flag.  */
        !           746: 
        !           747: rtx
        !           748: assign_stack_temp (mode, size, keep)
        !           749:      enum machine_mode mode;
        !           750:      int size;
        !           751:      int keep;
        !           752: {
        !           753:   struct temp_slot *p, *best_p = 0;
        !           754: 
        !           755:   /* First try to find an available, already-allocated temporary that is the
        !           756:      exact size we require.  */
        !           757:   for (p = temp_slots; p; p = p->next)
        !           758:     if (p->size == size && GET_MODE (p->slot) == mode && ! p->in_use)
        !           759:       break;
        !           760: 
        !           761:   /* If we didn't find, one, try one that is larger than what we want.  We
        !           762:      find the smallest such.  */
        !           763:   if (p == 0)
        !           764:     for (p = temp_slots; p; p = p->next)
        !           765:       if (p->size > size && GET_MODE (p->slot) == mode && ! p->in_use
        !           766:          && (best_p == 0 || best_p->size > p->size))
        !           767:        best_p = p;
        !           768: 
        !           769:   /* Make our best, if any, the one to use.  */
        !           770:   if (best_p)
        !           771:     {
        !           772:       /* If there are enough aligned bytes left over, make them into a new
        !           773:         temp_slot so that the extra bytes don't get wasted.  Do this only
        !           774:         for BLKmode slots, so that we can be sure of the alignment.  */
        !           775:       if (GET_MODE (best_p->slot) == BLKmode)
        !           776:        {
        !           777:          int alignment = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
        !           778:          int rounded_size = CEIL_ROUND (size, alignment);
        !           779: 
        !           780:          if (best_p->size - rounded_size >= alignment)
        !           781:            {
        !           782:              p = (struct temp_slot *) oballoc (sizeof (struct temp_slot));
        !           783:              p->in_use = 0;
        !           784:              p->size = best_p->size - rounded_size;
        !           785:              p->slot = gen_rtx (MEM, BLKmode,
        !           786:                                 plus_constant (XEXP (best_p->slot, 0),
        !           787:                                                rounded_size));
        !           788:              p->next = temp_slots;
        !           789:              temp_slots = p;
        !           790: 
        !           791:              stack_slot_list = gen_rtx (EXPR_LIST, VOIDmode, p->slot,
        !           792:                                         stack_slot_list);
        !           793: 
        !           794:              best_p->size = rounded_size;
        !           795:            }
        !           796:        }
        !           797: 
        !           798:       p = best_p;
        !           799:     }
        !           800:              
        !           801: 
        !           802:   /* If we still didn't find one, make a new temporary.  */
        !           803:   if (p == 0)
        !           804:     {
        !           805:       p = (struct temp_slot *) oballoc (sizeof (struct temp_slot));
        !           806:       p->size = size;
        !           807:       /* If the temp slot mode doesn't indicate the alignment,
        !           808:         use the largest possible, so no one will be disappointed.  */
        !           809:       p->slot = assign_stack_local (mode, size, mode == BLKmode ? -1 : 0); 
        !           810:       p->next = temp_slots;
        !           811:       temp_slots = p;
        !           812:     }
        !           813: 
        !           814:   p->in_use = 1;
        !           815:   p->rtl_expr = sequence_rtl_expr;
        !           816:   p->level = temp_slot_level;
        !           817:   p->keep = keep;
        !           818:   return p->slot;
        !           819: }
        !           820: 
        !           821: /* Combine temporary stack slots which are adjacent on the stack.
        !           822: 
        !           823:    This allows for better use of already allocated stack space.  This is only
        !           824:    done for BLKmode slots because we can be sure that we won't have alignment
        !           825:    problems in this case.  */
        !           826: 
        !           827: void
        !           828: combine_temp_slots ()
        !           829: {
        !           830:   struct temp_slot *p, *q;
        !           831:   struct temp_slot *prev_p, *prev_q;
        !           832:   /* Determine where to free back to after this function.  */
        !           833:   rtx free_pointer = rtx_alloc (CONST_INT);
        !           834: 
        !           835:   for (p = temp_slots, prev_p = 0; p; p = prev_p ? prev_p->next : temp_slots)
        !           836:     {
        !           837:       int delete_p = 0;
        !           838:       if (! p->in_use && GET_MODE (p->slot) == BLKmode)
        !           839:        for (q = p->next, prev_q = p; q; q = prev_q->next)
        !           840:          {
        !           841:            int delete_q = 0;
        !           842:            if (! q->in_use && GET_MODE (q->slot) == BLKmode)
        !           843:              {
        !           844:                if (rtx_equal_p (plus_constant (XEXP (p->slot, 0), p->size),
        !           845:                                 XEXP (q->slot, 0)))
        !           846:                  {
        !           847:                    /* Q comes after P; combine Q into P.  */
        !           848:                    p->size += q->size;
        !           849:                    delete_q = 1;
        !           850:                  }
        !           851:                else if (rtx_equal_p (plus_constant (XEXP (q->slot, 0), q->size),
        !           852:                                      XEXP (p->slot, 0)))
        !           853:                  {
        !           854:                    /* P comes after Q; combine P into Q.  */
        !           855:                    q->size += p->size;
        !           856:                    delete_p = 1;
        !           857:                    break;
        !           858:                  }
        !           859:              }
        !           860:            /* Either delete Q or advance past it.  */
        !           861:            if (delete_q)
        !           862:              prev_q->next = q->next;
        !           863:            else
        !           864:              prev_q = q;
        !           865:          }
        !           866:       /* Either delete P or advance past it.  */
        !           867:       if (delete_p)
        !           868:        {
        !           869:          if (prev_p)
        !           870:            prev_p->next = p->next;
        !           871:          else
        !           872:            temp_slots = p->next;
        !           873:        }
        !           874:       else
        !           875:        prev_p = p;
        !           876:     }
        !           877: 
        !           878:   /* Free all the RTL made by plus_constant.  */ 
        !           879:   rtx_free (free_pointer);
        !           880: }
        !           881: 
        !           882: /* If X could be a reference to a temporary slot, mark that slot as belonging
        !           883:    to the to one level higher.  If X matched one of our slots, just mark that
        !           884:    one.  Otherwise, we can't easily predict which it is, so upgrade all of
        !           885:    them.  Kept slots need not be touched.
        !           886: 
        !           887:    This is called when an ({...}) construct occurs and a statement
        !           888:    returns a value in memory.  */
        !           889: 
        !           890: void
        !           891: preserve_temp_slots (x)
        !           892:      rtx x;
        !           893: {
        !           894:   struct temp_slot *p;
        !           895: 
        !           896:   /* If X is not in memory or is at a constant address, it cannot be in
        !           897:      a temporary slot.  */
        !           898:   if (x == 0 || GET_CODE (x) != MEM || CONSTANT_P (XEXP (x, 0)))
        !           899:     return;
        !           900: 
        !           901:   /* First see if we can find a match.  */
        !           902:   for (p = temp_slots; p; p = p->next)
        !           903:     if (p->in_use && x == p->slot)
        !           904:       {
        !           905:        p->level--;
        !           906:        return;
        !           907:       }
        !           908: 
        !           909:   /* Otherwise, preserve all non-kept slots at this level.  */
        !           910:   for (p = temp_slots; p; p = p->next)
        !           911:     if (p->in_use && p->level == temp_slot_level && ! p->keep)
        !           912:       p->level--;
        !           913: }
        !           914: 
        !           915: /* Free all temporaries used so far.  This is normally called at the end
        !           916:    of generating code for a statement.  Don't free any temporaries
        !           917:    currently in use for an RTL_EXPR that hasn't yet been emitted.
        !           918:    We could eventually do better than this since it can be reused while
        !           919:    generating the same RTL_EXPR, but this is complex and probably not
        !           920:    worthwhile.  */
        !           921: 
        !           922: void
        !           923: free_temp_slots ()
        !           924: {
        !           925:   struct temp_slot *p;
        !           926: 
        !           927:   for (p = temp_slots; p; p = p->next)
        !           928:     if (p->in_use && p->level == temp_slot_level && ! p->keep
        !           929:        && p->rtl_expr == 0)
        !           930:       p->in_use = 0;
        !           931: 
        !           932:   combine_temp_slots ();
        !           933: }
        !           934: 
        !           935: /* Free all temporary slots used in T, an RTL_EXPR node.  */
        !           936: 
        !           937: void
        !           938: free_temps_for_rtl_expr (t)
        !           939:      tree t;
        !           940: {
        !           941:   struct temp_slot *p;
        !           942: 
        !           943:   for (p = temp_slots; p; p = p->next)
        !           944:     if (p->rtl_expr == t)
        !           945:       p->in_use = 0;
        !           946: 
        !           947:   combine_temp_slots ();
        !           948: }
        !           949: 
        !           950: /* Push deeper into the nesting level for stack temporaries.  */
        !           951: 
        !           952: void
        !           953: push_temp_slots ()
        !           954: {
        !           955:   temp_slot_level++;
        !           956: }
        !           957: 
        !           958: /* Pop a temporary nesting level.  All slots in use in the current level
        !           959:    are freed.  */
        !           960: 
        !           961: void
        !           962: pop_temp_slots ()
        !           963: {
        !           964:   struct temp_slot *p;
        !           965: 
        !           966:   for (p = temp_slots; p; p = p->next)
        !           967:     if (p->in_use && p->level == temp_slot_level && p->rtl_expr == 0)
        !           968:       p->in_use = 0;
        !           969: 
        !           970:   combine_temp_slots ();
        !           971: 
        !           972:   temp_slot_level--;
        !           973: }
        !           974: 
        !           975: /* Retroactively move an auto variable from a register to a stack slot.
        !           976:    This is done when an address-reference to the variable is seen.  */
        !           977: 
        !           978: void
        !           979: put_var_into_stack (decl)
        !           980:      tree decl;
        !           981: {
        !           982:   register rtx reg;
        !           983:   enum machine_mode promoted_mode, decl_mode;
        !           984:   struct function *function = 0;
        !           985:   tree context;
        !           986: 
        !           987:   if (output_bytecode)
        !           988:     return;
        !           989:   
        !           990:   context = decl_function_context (decl);
        !           991: 
        !           992:   /* Get the current rtl used for this object and it's original mode.  */
        !           993:   reg = TREE_CODE (decl) == SAVE_EXPR ? SAVE_EXPR_RTL (decl) : DECL_RTL (decl);
        !           994: 
        !           995:   /* No need to do anything if decl has no rtx yet
        !           996:      since in that case caller is setting TREE_ADDRESSABLE
        !           997:      and a stack slot will be assigned when the rtl is made.  */
        !           998:   if (reg == 0)
        !           999:     return;
        !          1000: 
        !          1001:   /* Get the declared mode for this object.  */
        !          1002:   decl_mode = (TREE_CODE (decl) == SAVE_EXPR ? TYPE_MODE (TREE_TYPE (decl))
        !          1003:               : DECL_MODE (decl));
        !          1004:   /* Get the mode it's actually stored in.  */
        !          1005:   promoted_mode = GET_MODE (reg);
        !          1006: 
        !          1007:   /* If this variable comes from an outer function,
        !          1008:      find that function's saved context.  */
        !          1009:   if (context != current_function_decl)
        !          1010:     for (function = outer_function_chain; function; function = function->next)
        !          1011:       if (function->decl == context)
        !          1012:        break;
        !          1013: 
        !          1014:   /* If this is a variable-size object with a pseudo to address it,
        !          1015:      put that pseudo into the stack, if the var is nonlocal.  */
        !          1016:   if (DECL_NONLOCAL (decl)
        !          1017:       && GET_CODE (reg) == MEM
        !          1018:       && GET_CODE (XEXP (reg, 0)) == REG
        !          1019:       && REGNO (XEXP (reg, 0)) > LAST_VIRTUAL_REGISTER)
        !          1020:     {
        !          1021:       reg = XEXP (reg, 0);
        !          1022:       decl_mode = promoted_mode = GET_MODE (reg);
        !          1023:     }
        !          1024: 
        !          1025:   /* Now we should have a value that resides in one or more pseudo regs.  */
        !          1026: 
        !          1027:   if (GET_CODE (reg) == REG)
        !          1028:     put_reg_into_stack (function, reg, TREE_TYPE (decl),
        !          1029:                        promoted_mode, decl_mode);
        !          1030:   else if (GET_CODE (reg) == CONCAT)
        !          1031:     {
        !          1032:       /* A CONCAT contains two pseudos; put them both in the stack.
        !          1033:         We do it so they end up consecutive.  */
        !          1034:       enum machine_mode part_mode = GET_MODE (XEXP (reg, 0));
        !          1035:       tree part_type = TREE_TYPE (TREE_TYPE (decl));
        !          1036: #ifdef STACK_GROWS_DOWNWARD
        !          1037:       /* Since part 0 should have a lower address, do it second.  */
        !          1038:       put_reg_into_stack (function, XEXP (reg, 1),
        !          1039:                          part_type, part_mode, part_mode);
        !          1040:       put_reg_into_stack (function, XEXP (reg, 0),
        !          1041:                          part_type, part_mode, part_mode);
        !          1042: #else
        !          1043:       put_reg_into_stack (function, XEXP (reg, 0),
        !          1044:                          part_type, part_mode, part_mode);
        !          1045:       put_reg_into_stack (function, XEXP (reg, 1),
        !          1046:                          part_type, part_mode, part_mode);
        !          1047: #endif
        !          1048: 
        !          1049:       /* Change the CONCAT into a combined MEM for both parts.  */
        !          1050:       PUT_CODE (reg, MEM);
        !          1051:       /* The two parts are in memory order already.
        !          1052:         Use the lower parts address as ours.  */
        !          1053:       XEXP (reg, 0) = XEXP (XEXP (reg, 0), 0);
        !          1054:       /* Prevent sharing of rtl that might lose.  */
        !          1055:       if (GET_CODE (XEXP (reg, 0)) == PLUS)
        !          1056:        XEXP (reg, 0) = copy_rtx (XEXP (reg, 0));
        !          1057:     }
        !          1058: }
        !          1059: 
        !          1060: /* Subroutine of put_var_into_stack.  This puts a single pseudo reg REG
        !          1061:    into the stack frame of FUNCTION (0 means the current function).
        !          1062:    DECL_MODE is the machine mode of the user-level data type.
        !          1063:    PROMOTED_MODE is the machine mode of the register.  */
        !          1064: 
        !          1065: static void
        !          1066: put_reg_into_stack (function, reg, type, promoted_mode, decl_mode)
        !          1067:      struct function *function;
        !          1068:      rtx reg;
        !          1069:      tree type;
        !          1070:      enum machine_mode promoted_mode, decl_mode;
        !          1071: {
        !          1072:   rtx new = 0;
        !          1073: 
        !          1074:   if (function)
        !          1075:     {
        !          1076:       if (REGNO (reg) < function->max_parm_reg)
        !          1077:        new = function->parm_reg_stack_loc[REGNO (reg)];
        !          1078:       if (new == 0)
        !          1079:        new = assign_outer_stack_local (decl_mode, GET_MODE_SIZE (decl_mode),
        !          1080:                                        0, function);
        !          1081:     }
        !          1082:   else
        !          1083:     {
        !          1084:       if (REGNO (reg) < max_parm_reg)
        !          1085:        new = parm_reg_stack_loc[REGNO (reg)];
        !          1086:       if (new == 0)
        !          1087:        new = assign_stack_local (decl_mode, GET_MODE_SIZE (decl_mode), 0);
        !          1088:     }
        !          1089: 
        !          1090:   XEXP (reg, 0) = XEXP (new, 0);
        !          1091:   /* `volatil' bit means one thing for MEMs, another entirely for REGs.  */
        !          1092:   REG_USERVAR_P (reg) = 0;
        !          1093:   PUT_CODE (reg, MEM);
        !          1094:   PUT_MODE (reg, decl_mode);
        !          1095: 
        !          1096:   /* If this is a memory ref that contains aggregate components,
        !          1097:      mark it as such for cse and loop optimize.  */
        !          1098:   MEM_IN_STRUCT_P (reg)
        !          1099:     = (TREE_CODE (type) == ARRAY_TYPE
        !          1100:        || TREE_CODE (type) == RECORD_TYPE
        !          1101:        || TREE_CODE (type) == UNION_TYPE
        !          1102:        || TREE_CODE (type) == QUAL_UNION_TYPE);
        !          1103: 
        !          1104:   /* Now make sure that all refs to the variable, previously made
        !          1105:      when it was a register, are fixed up to be valid again.  */
        !          1106:   if (function)
        !          1107:     {
        !          1108:       struct var_refs_queue *temp;
        !          1109: 
        !          1110:       /* Variable is inherited; fix it up when we get back to its function.  */
        !          1111:       push_obstacks (function->function_obstack,
        !          1112:                     function->function_maybepermanent_obstack);
        !          1113: 
        !          1114:       /* See comment in restore_tree_status in tree.c for why this needs to be
        !          1115:         on saveable obstack.  */
        !          1116:       temp
        !          1117:        = (struct var_refs_queue *) savealloc (sizeof (struct var_refs_queue));
        !          1118:       temp->modified = reg;
        !          1119:       temp->promoted_mode = promoted_mode;
        !          1120:       temp->unsignedp = TREE_UNSIGNED (type);
        !          1121:       temp->next = function->fixup_var_refs_queue;
        !          1122:       function->fixup_var_refs_queue = temp;
        !          1123:       pop_obstacks ();
        !          1124:     }
        !          1125:   else
        !          1126:     /* Variable is local; fix it up now.  */
        !          1127:     fixup_var_refs (reg, promoted_mode, TREE_UNSIGNED (type));
        !          1128: }
        !          1129: 
        !          1130: static void
        !          1131: fixup_var_refs (var, promoted_mode, unsignedp)
        !          1132:      rtx var;
        !          1133:      enum machine_mode promoted_mode;
        !          1134:      int unsignedp;
        !          1135: {
        !          1136:   tree pending;
        !          1137:   rtx first_insn = get_insns ();
        !          1138:   struct sequence_stack *stack = sequence_stack;
        !          1139:   tree rtl_exps = rtl_expr_chain;
        !          1140: 
        !          1141:   /* Must scan all insns for stack-refs that exceed the limit.  */
        !          1142:   fixup_var_refs_insns (var, promoted_mode, unsignedp, first_insn, stack == 0);
        !          1143: 
        !          1144:   /* Scan all pending sequences too.  */
        !          1145:   for (; stack; stack = stack->next)
        !          1146:     {
        !          1147:       push_to_sequence (stack->first);
        !          1148:       fixup_var_refs_insns (var, promoted_mode, unsignedp,
        !          1149:                            stack->first, stack->next != 0);
        !          1150:       /* Update remembered end of sequence
        !          1151:         in case we added an insn at the end.  */
        !          1152:       stack->last = get_last_insn ();
        !          1153:       end_sequence ();
        !          1154:     }
        !          1155: 
        !          1156:   /* Scan all waiting RTL_EXPRs too.  */
        !          1157:   for (pending = rtl_exps; pending; pending = TREE_CHAIN (pending))
        !          1158:     {
        !          1159:       rtx seq = RTL_EXPR_SEQUENCE (TREE_VALUE (pending));
        !          1160:       if (seq != const0_rtx && seq != 0)
        !          1161:        {
        !          1162:          push_to_sequence (seq);
        !          1163:          fixup_var_refs_insns (var, promoted_mode, unsignedp, seq, 0);
        !          1164:          end_sequence ();
        !          1165:        }
        !          1166:     }
        !          1167: }
        !          1168: 
        !          1169: /* This structure is used by the following two functions to record MEMs or
        !          1170:    pseudos used to replace VAR, any SUBREGs of VAR, and any MEMs containing
        !          1171:    VAR as an address.  We need to maintain this list in case two operands of
        !          1172:    an insn were required to match; in that case we must ensure we use the
        !          1173:    same replacement.  */
        !          1174: 
        !          1175: struct fixup_replacement
        !          1176: {
        !          1177:   rtx old;
        !          1178:   rtx new;
        !          1179:   struct fixup_replacement *next;
        !          1180: };
        !          1181:    
        !          1182: /* REPLACEMENTS is a pointer to a list of the above structures and X is
        !          1183:    some part of an insn.  Return a struct fixup_replacement whose OLD
        !          1184:    value is equal to X.  Allocate a new structure if no such entry exists. */
        !          1185: 
        !          1186: static struct fixup_replacement *
        !          1187: find_fixup_replacement (replacements, x)
        !          1188:      struct fixup_replacement **replacements;
        !          1189:      rtx x;
        !          1190: {
        !          1191:   struct fixup_replacement *p;
        !          1192: 
        !          1193:   /* See if we have already replaced this.  */
        !          1194:   for (p = *replacements; p && p->old != x; p = p->next)
        !          1195:     ;
        !          1196: 
        !          1197:   if (p == 0)
        !          1198:     {
        !          1199:       p = (struct fixup_replacement *) oballoc (sizeof (struct fixup_replacement));
        !          1200:       p->old = x;
        !          1201:       p->new = 0;
        !          1202:       p->next = *replacements;
        !          1203:       *replacements = p;
        !          1204:     }
        !          1205: 
        !          1206:   return p;
        !          1207: }
        !          1208: 
        !          1209: /* Scan the insn-chain starting with INSN for refs to VAR
        !          1210:    and fix them up.  TOPLEVEL is nonzero if this chain is the
        !          1211:    main chain of insns for the current function.  */
        !          1212: 
        !          1213: static void
        !          1214: fixup_var_refs_insns (var, promoted_mode, unsignedp, insn, toplevel)
        !          1215:      rtx var;
        !          1216:      enum machine_mode promoted_mode;
        !          1217:      int unsignedp;
        !          1218:      rtx insn;
        !          1219:      int toplevel;
        !          1220: {
        !          1221:   rtx call_dest = 0;
        !          1222: 
        !          1223:   while (insn)
        !          1224:     {
        !          1225:       rtx next = NEXT_INSN (insn);
        !          1226:       rtx note;
        !          1227:       if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
        !          1228:        {
        !          1229:          /* The insn to load VAR from a home in the arglist
        !          1230:             is now a no-op.  When we see it, just delete it.  */
        !          1231:          if (toplevel
        !          1232:              && GET_CODE (PATTERN (insn)) == SET
        !          1233:              && SET_DEST (PATTERN (insn)) == var
        !          1234:              /* If this represents the result of an insn group,
        !          1235:                 don't delete the insn.  */
        !          1236:              && find_reg_note (insn, REG_RETVAL, NULL_RTX) == 0
        !          1237:              && rtx_equal_p (SET_SRC (PATTERN (insn)), var))
        !          1238:            {
        !          1239:              /* In unoptimized compilation, we shouldn't call delete_insn
        !          1240:                 except in jump.c doing warnings.  */
        !          1241:              PUT_CODE (insn, NOTE);
        !          1242:              NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
        !          1243:              NOTE_SOURCE_FILE (insn) = 0;
        !          1244:              if (insn == last_parm_insn)
        !          1245:                last_parm_insn = PREV_INSN (next);
        !          1246:            }
        !          1247:          else
        !          1248:            {
        !          1249:              struct fixup_replacement *replacements = 0;
        !          1250:              rtx next_insn = NEXT_INSN (insn);
        !          1251: 
        !          1252: #ifdef SMALL_REGISTER_CLASSES
        !          1253:              /* If the insn that copies the results of a CALL_INSN
        !          1254:                 into a pseudo now references VAR, we have to use an
        !          1255:                 intermediate pseudo since we want the life of the
        !          1256:                 return value register to be only a single insn.
        !          1257: 
        !          1258:                 If we don't use an intermediate pseudo, such things as
        !          1259:                 address computations to make the address of VAR valid
        !          1260:                 if it is not can be placed beween the CALL_INSN and INSN.
        !          1261: 
        !          1262:                 To make sure this doesn't happen, we record the destination
        !          1263:                 of the CALL_INSN and see if the next insn uses both that
        !          1264:                 and VAR.  */
        !          1265: 
        !          1266:              if (call_dest != 0 && GET_CODE (insn) == INSN
        !          1267:                  && reg_mentioned_p (var, PATTERN (insn))
        !          1268:                  && reg_mentioned_p (call_dest, PATTERN (insn)))
        !          1269:                {
        !          1270:                  rtx temp = gen_reg_rtx (GET_MODE (call_dest));
        !          1271: 
        !          1272:                  emit_insn_before (gen_move_insn (temp, call_dest), insn);
        !          1273: 
        !          1274:                  PATTERN (insn) = replace_rtx (PATTERN (insn),
        !          1275:                                                call_dest, temp);
        !          1276:                }
        !          1277:              
        !          1278:              if (GET_CODE (insn) == CALL_INSN
        !          1279:                  && GET_CODE (PATTERN (insn)) == SET)
        !          1280:                call_dest = SET_DEST (PATTERN (insn));
        !          1281:              else if (GET_CODE (insn) == CALL_INSN
        !          1282:                       && GET_CODE (PATTERN (insn)) == PARALLEL
        !          1283:                       && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET)
        !          1284:                call_dest = SET_DEST (XVECEXP (PATTERN (insn), 0, 0));
        !          1285:              else
        !          1286:                call_dest = 0;
        !          1287: #endif
        !          1288: 
        !          1289:              /* See if we have to do anything to INSN now that VAR is in
        !          1290:                 memory.  If it needs to be loaded into a pseudo, use a single
        !          1291:                 pseudo for the entire insn in case there is a MATCH_DUP
        !          1292:                 between two operands.  We pass a pointer to the head of
        !          1293:                 a list of struct fixup_replacements.  If fixup_var_refs_1
        !          1294:                 needs to allocate pseudos or replacement MEMs (for SUBREGs),
        !          1295:                 it will record them in this list.
        !          1296:                 
        !          1297:                 If it allocated a pseudo for any replacement, we copy into
        !          1298:                 it here.  */
        !          1299: 
        !          1300:              fixup_var_refs_1 (var, promoted_mode, &PATTERN (insn), insn,
        !          1301:                                &replacements);
        !          1302: 
        !          1303:              /* If this is last_parm_insn, and any instructions were output
        !          1304:                 after it to fix it up, then we must set last_parm_insn to
        !          1305:                 the last such instruction emitted.  */
        !          1306:              if (insn == last_parm_insn)
        !          1307:                last_parm_insn = PREV_INSN (next_insn);
        !          1308: 
        !          1309:              while (replacements)
        !          1310:                {
        !          1311:                  if (GET_CODE (replacements->new) == REG)
        !          1312:                    {
        !          1313:                      rtx insert_before;
        !          1314:                      rtx seq;
        !          1315: 
        !          1316:                      /* OLD might be a (subreg (mem)).  */
        !          1317:                      if (GET_CODE (replacements->old) == SUBREG)
        !          1318:                        replacements->old
        !          1319:                          = fixup_memory_subreg (replacements->old, insn, 0);
        !          1320:                      else
        !          1321:                        replacements->old
        !          1322:                          = fixup_stack_1 (replacements->old, insn);
        !          1323: 
        !          1324:                      /* We can not separate USE insns from the CALL_INSN
        !          1325:                         that they belong to.  If this is a CALL_INSN, insert
        !          1326:                         the move insn before the USE insns preceding it
        !          1327:                         instead of immediately before the insn.  */
        !          1328:                      if (GET_CODE (insn) == CALL_INSN)
        !          1329:                        {
        !          1330:                          insert_before = insn;
        !          1331:                          while (GET_CODE (PREV_INSN (insert_before)) == INSN
        !          1332:                                 && GET_CODE (PATTERN (PREV_INSN (insert_before))) == USE)
        !          1333:                            insert_before = PREV_INSN (insert_before);
        !          1334:                        }
        !          1335:                      else
        !          1336:                        insert_before = insn;
        !          1337: 
        !          1338:                      /* If we are changing the mode, do a conversion.
        !          1339:                         This might be wasteful, but combine.c will
        !          1340:                         eliminate much of the waste.  */
        !          1341: 
        !          1342:                      if (GET_MODE (replacements->new)
        !          1343:                          != GET_MODE (replacements->old))
        !          1344:                        {
        !          1345:                          start_sequence ();
        !          1346:                          convert_move (replacements->new,
        !          1347:                                        replacements->old, unsignedp);
        !          1348:                          seq = gen_sequence ();
        !          1349:                          end_sequence ();
        !          1350:                        }
        !          1351:                      else
        !          1352:                        seq = gen_move_insn (replacements->new,
        !          1353:                                             replacements->old);
        !          1354: 
        !          1355:                      emit_insn_before (seq, insert_before);
        !          1356:                    }
        !          1357: 
        !          1358:                  replacements = replacements->next;
        !          1359:                }
        !          1360:            }
        !          1361: 
        !          1362:          /* Also fix up any invalid exprs in the REG_NOTES of this insn.
        !          1363:             But don't touch other insns referred to by reg-notes;
        !          1364:             we will get them elsewhere.  */
        !          1365:          for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
        !          1366:            if (GET_CODE (note) != INSN_LIST)
        !          1367:              XEXP (note, 0)
        !          1368:                = walk_fixup_memory_subreg (XEXP (note, 0), insn, 1);
        !          1369:        }
        !          1370:       insn = next;
        !          1371:     }
        !          1372: }
        !          1373: 
        !          1374: /* VAR is a MEM that used to be a pseudo register with mode PROMOTED_MODE.
        !          1375:    See if the rtx expression at *LOC in INSN needs to be changed.  
        !          1376: 
        !          1377:    REPLACEMENTS is a pointer to a list head that starts out zero, but may
        !          1378:    contain a list of original rtx's and replacements. If we find that we need
        !          1379:    to modify this insn by replacing a memory reference with a pseudo or by
        !          1380:    making a new MEM to implement a SUBREG, we consult that list to see if
        !          1381:    we have already chosen a replacement. If none has already been allocated,
        !          1382:    we allocate it and update the list.  fixup_var_refs_insns will copy VAR
        !          1383:    or the SUBREG, as appropriate, to the pseudo.  */
        !          1384: 
        !          1385: static void
        !          1386: fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
        !          1387:      register rtx var;
        !          1388:      enum machine_mode promoted_mode;
        !          1389:      register rtx *loc;
        !          1390:      rtx insn;
        !          1391:      struct fixup_replacement **replacements;
        !          1392: {
        !          1393:   register int i;
        !          1394:   register rtx x = *loc;
        !          1395:   RTX_CODE code = GET_CODE (x);
        !          1396:   register char *fmt;
        !          1397:   register rtx tem, tem1;
        !          1398:   struct fixup_replacement *replacement;
        !          1399: 
        !          1400:   switch (code)
        !          1401:     {
        !          1402:     case MEM:
        !          1403:       if (var == x)
        !          1404:        {
        !          1405:          /* If we already have a replacement, use it.  Otherwise, 
        !          1406:             try to fix up this address in case it is invalid.  */
        !          1407: 
        !          1408:          replacement = find_fixup_replacement (replacements, var);
        !          1409:          if (replacement->new)
        !          1410:            {
        !          1411:              *loc = replacement->new;
        !          1412:              return;
        !          1413:            }
        !          1414: 
        !          1415:          *loc = replacement->new = x = fixup_stack_1 (x, insn);
        !          1416: 
        !          1417:          /* Unless we are forcing memory to register or we changed the mode,
        !          1418:             we can leave things the way they are if the insn is valid.  */
        !          1419:             
        !          1420:          INSN_CODE (insn) = -1;
        !          1421:          if (! flag_force_mem && GET_MODE (x) == promoted_mode
        !          1422:              && recog_memoized (insn) >= 0)
        !          1423:            return;
        !          1424: 
        !          1425:          *loc = replacement->new = gen_reg_rtx (promoted_mode);
        !          1426:          return;
        !          1427:        }
        !          1428: 
        !          1429:       /* If X contains VAR, we need to unshare it here so that we update
        !          1430:         each occurrence separately.  But all identical MEMs in one insn
        !          1431:         must be replaced with the same rtx because of the possibility of
        !          1432:         MATCH_DUPs.  */
        !          1433: 
        !          1434:       if (reg_mentioned_p (var, x))
        !          1435:        {
        !          1436:          replacement = find_fixup_replacement (replacements, x);
        !          1437:          if (replacement->new == 0)
        !          1438:            replacement->new = copy_most_rtx (x, var);
        !          1439: 
        !          1440:          *loc = x = replacement->new;
        !          1441:        }
        !          1442:       break;
        !          1443: 
        !          1444:     case REG:
        !          1445:     case CC0:
        !          1446:     case PC:
        !          1447:     case CONST_INT:
        !          1448:     case CONST:
        !          1449:     case SYMBOL_REF:
        !          1450:     case LABEL_REF:
        !          1451:     case CONST_DOUBLE:
        !          1452:       return;
        !          1453: 
        !          1454:     case SIGN_EXTRACT:
        !          1455:     case ZERO_EXTRACT:
        !          1456:       /* Note that in some cases those types of expressions are altered
        !          1457:         by optimize_bit_field, and do not survive to get here.  */
        !          1458:       if (XEXP (x, 0) == var
        !          1459:          || (GET_CODE (XEXP (x, 0)) == SUBREG
        !          1460:              && SUBREG_REG (XEXP (x, 0)) == var))
        !          1461:        {
        !          1462:          /* Get TEM as a valid MEM in the mode presently in the insn.
        !          1463: 
        !          1464:             We don't worry about the possibility of MATCH_DUP here; it
        !          1465:             is highly unlikely and would be tricky to handle.  */
        !          1466: 
        !          1467:          tem = XEXP (x, 0);
        !          1468:          if (GET_CODE (tem) == SUBREG)
        !          1469:            tem = fixup_memory_subreg (tem, insn, 1);
        !          1470:          tem = fixup_stack_1 (tem, insn);
        !          1471: 
        !          1472:          /* Unless we want to load from memory, get TEM into the proper mode
        !          1473:             for an extract from memory.  This can only be done if the
        !          1474:             extract is at a constant position and length.  */
        !          1475: 
        !          1476:          if (! flag_force_mem && GET_CODE (XEXP (x, 1)) == CONST_INT
        !          1477:              && GET_CODE (XEXP (x, 2)) == CONST_INT
        !          1478:              && ! mode_dependent_address_p (XEXP (tem, 0))
        !          1479:              && ! MEM_VOLATILE_P (tem))
        !          1480:            {
        !          1481:              enum machine_mode wanted_mode = VOIDmode;
        !          1482:              enum machine_mode is_mode = GET_MODE (tem);
        !          1483:              int width = INTVAL (XEXP (x, 1));
        !          1484:              int pos = INTVAL (XEXP (x, 2));
        !          1485: 
        !          1486: #ifdef HAVE_extzv
        !          1487:              if (GET_CODE (x) == ZERO_EXTRACT)
        !          1488:                wanted_mode = insn_operand_mode[(int) CODE_FOR_extzv][1];
        !          1489: #endif
        !          1490: #ifdef HAVE_extv
        !          1491:              if (GET_CODE (x) == SIGN_EXTRACT)
        !          1492:                wanted_mode = insn_operand_mode[(int) CODE_FOR_extv][1];
        !          1493: #endif
        !          1494:              /* If we have a narrower mode, we can do something.  */
        !          1495:              if (wanted_mode != VOIDmode
        !          1496:                  && GET_MODE_SIZE (wanted_mode) < GET_MODE_SIZE (is_mode))
        !          1497:                {
        !          1498:                  int offset = pos / BITS_PER_UNIT;
        !          1499:                  rtx old_pos = XEXP (x, 2);
        !          1500:                  rtx newmem;
        !          1501: 
        !          1502:                  /* If the bytes and bits are counted differently, we
        !          1503:                     must adjust the offset.  */
        !          1504: #if BYTES_BIG_ENDIAN != BITS_BIG_ENDIAN
        !          1505:                  offset = (GET_MODE_SIZE (is_mode)
        !          1506:                            - GET_MODE_SIZE (wanted_mode) - offset);
        !          1507: #endif
        !          1508: 
        !          1509:                  pos %= GET_MODE_BITSIZE (wanted_mode);
        !          1510: 
        !          1511:                  newmem = gen_rtx (MEM, wanted_mode,
        !          1512:                                    plus_constant (XEXP (tem, 0), offset));
        !          1513:                  RTX_UNCHANGING_P (newmem) = RTX_UNCHANGING_P (tem);
        !          1514:                  MEM_VOLATILE_P (newmem) = MEM_VOLATILE_P (tem);
        !          1515:                  MEM_IN_STRUCT_P (newmem) = MEM_IN_STRUCT_P (tem);
        !          1516: 
        !          1517:                  /* Make the change and see if the insn remains valid.  */
        !          1518:                  INSN_CODE (insn) = -1;
        !          1519:                  XEXP (x, 0) = newmem;
        !          1520:                  XEXP (x, 2) = GEN_INT (pos);
        !          1521: 
        !          1522:                  if (recog_memoized (insn) >= 0)
        !          1523:                    return;
        !          1524: 
        !          1525:                  /* Otherwise, restore old position.  XEXP (x, 0) will be
        !          1526:                     restored later.  */
        !          1527:                  XEXP (x, 2) = old_pos;
        !          1528:                }
        !          1529:            }
        !          1530: 
        !          1531:          /* If we get here, the bitfield extract insn can't accept a memory
        !          1532:             reference.  Copy the input into a register.  */
        !          1533: 
        !          1534:          tem1 = gen_reg_rtx (GET_MODE (tem));
        !          1535:          emit_insn_before (gen_move_insn (tem1, tem), insn);
        !          1536:          XEXP (x, 0) = tem1;
        !          1537:          return;
        !          1538:        }
        !          1539:       break;
        !          1540:              
        !          1541:     case SUBREG:
        !          1542:       if (SUBREG_REG (x) == var)
        !          1543:        {
        !          1544:          /* If this is a special SUBREG made because VAR was promoted
        !          1545:             from a wider mode, replace it with VAR and call ourself
        !          1546:             recursively, this time saying that the object previously
        !          1547:             had its current mode (by virtue of the SUBREG).  */
        !          1548: 
        !          1549:          if (SUBREG_PROMOTED_VAR_P (x))
        !          1550:            {
        !          1551:              *loc = var;
        !          1552:              fixup_var_refs_1 (var, GET_MODE (var), loc, insn, replacements);
        !          1553:              return;
        !          1554:            }
        !          1555: 
        !          1556:          /* If this SUBREG makes VAR wider, it has become a paradoxical
        !          1557:             SUBREG with VAR in memory, but these aren't allowed at this 
        !          1558:             stage of the compilation.  So load VAR into a pseudo and take
        !          1559:             a SUBREG of that pseudo.  */
        !          1560:          if (GET_MODE_SIZE (GET_MODE (x)) > GET_MODE_SIZE (GET_MODE (var)))
        !          1561:            {
        !          1562:              replacement = find_fixup_replacement (replacements, var);
        !          1563:              if (replacement->new == 0)
        !          1564:                replacement->new = gen_reg_rtx (GET_MODE (var));
        !          1565:              SUBREG_REG (x) = replacement->new;
        !          1566:              return;
        !          1567:            }
        !          1568: 
        !          1569:          /* See if we have already found a replacement for this SUBREG.
        !          1570:             If so, use it.  Otherwise, make a MEM and see if the insn
        !          1571:             is recognized.  If not, or if we should force MEM into a register,
        !          1572:             make a pseudo for this SUBREG.  */
        !          1573:          replacement = find_fixup_replacement (replacements, x);
        !          1574:          if (replacement->new)
        !          1575:            {
        !          1576:              *loc = replacement->new;
        !          1577:              return;
        !          1578:            }
        !          1579:          
        !          1580:          replacement->new = *loc = fixup_memory_subreg (x, insn, 0);
        !          1581: 
        !          1582:          INSN_CODE (insn) = -1;
        !          1583:          if (! flag_force_mem && recog_memoized (insn) >= 0)
        !          1584:            return;
        !          1585: 
        !          1586:          *loc = replacement->new = gen_reg_rtx (GET_MODE (x));
        !          1587:          return;
        !          1588:        }
        !          1589:       break;
        !          1590: 
        !          1591:     case SET:
        !          1592:       /* First do special simplification of bit-field references.  */
        !          1593:       if (GET_CODE (SET_DEST (x)) == SIGN_EXTRACT
        !          1594:          || GET_CODE (SET_DEST (x)) == ZERO_EXTRACT)
        !          1595:        optimize_bit_field (x, insn, 0);
        !          1596:       if (GET_CODE (SET_SRC (x)) == SIGN_EXTRACT
        !          1597:          || GET_CODE (SET_SRC (x)) == ZERO_EXTRACT)
        !          1598:        optimize_bit_field (x, insn, NULL_PTR);
        !          1599: 
        !          1600:       /* If SET_DEST is now a paradoxical SUBREG, put the result of this
        !          1601:         insn into a pseudo and store the low part of the pseudo into VAR. */
        !          1602:       if (GET_CODE (SET_DEST (x)) == SUBREG
        !          1603:          && SUBREG_REG (SET_DEST (x)) == var
        !          1604:          && (GET_MODE_SIZE (GET_MODE (SET_DEST (x)))
        !          1605:              > GET_MODE_SIZE (GET_MODE (var))))
        !          1606:        {
        !          1607:          SET_DEST (x) = tem = gen_reg_rtx (GET_MODE (SET_DEST (x)));
        !          1608:          emit_insn_after (gen_move_insn (var, gen_lowpart (GET_MODE (var),
        !          1609:                                                            tem)),
        !          1610:                           insn);
        !          1611:          break;
        !          1612:        }
        !          1613:          
        !          1614:       {
        !          1615:        rtx dest = SET_DEST (x);
        !          1616:        rtx src = SET_SRC (x);
        !          1617:        rtx outerdest = dest;
        !          1618: 
        !          1619:        while (GET_CODE (dest) == SUBREG || GET_CODE (dest) == STRICT_LOW_PART
        !          1620:               || GET_CODE (dest) == SIGN_EXTRACT
        !          1621:               || GET_CODE (dest) == ZERO_EXTRACT)
        !          1622:          dest = XEXP (dest, 0);
        !          1623: 
        !          1624:        if (GET_CODE (src) == SUBREG)
        !          1625:          src = XEXP (src, 0);
        !          1626: 
        !          1627:        /* If VAR does not appear at the top level of the SET
        !          1628:           just scan the lower levels of the tree.  */
        !          1629: 
        !          1630:         if (src != var && dest != var)
        !          1631:          break;
        !          1632: 
        !          1633:        /* We will need to rerecognize this insn.  */
        !          1634:        INSN_CODE (insn) = -1;
        !          1635: 
        !          1636: #ifdef HAVE_insv
        !          1637:        if (GET_CODE (outerdest) == ZERO_EXTRACT && dest == var)
        !          1638:          {
        !          1639:            /* Since this case will return, ensure we fixup all the
        !          1640:               operands here.  */
        !          1641:            fixup_var_refs_1 (var, promoted_mode, &XEXP (outerdest, 1),
        !          1642:                              insn, replacements);
        !          1643:            fixup_var_refs_1 (var, promoted_mode, &XEXP (outerdest, 2),
        !          1644:                              insn, replacements);
        !          1645:            fixup_var_refs_1 (var, promoted_mode, &SET_SRC (x),
        !          1646:                              insn, replacements);
        !          1647: 
        !          1648:            tem = XEXP (outerdest, 0);
        !          1649: 
        !          1650:            /* Clean up (SUBREG:SI (MEM:mode ...) 0)
        !          1651:               that may appear inside a ZERO_EXTRACT.
        !          1652:               This was legitimate when the MEM was a REG.  */
        !          1653:            if (GET_CODE (tem) == SUBREG
        !          1654:                && SUBREG_REG (tem) == var)
        !          1655:              tem = fixup_memory_subreg (tem, insn, 1);
        !          1656:            else
        !          1657:              tem = fixup_stack_1 (tem, insn);
        !          1658: 
        !          1659:            if (GET_CODE (XEXP (outerdest, 1)) == CONST_INT
        !          1660:                && GET_CODE (XEXP (outerdest, 2)) == CONST_INT
        !          1661:                && ! mode_dependent_address_p (XEXP (tem, 0))
        !          1662:                && ! MEM_VOLATILE_P (tem))
        !          1663:              {
        !          1664:                enum machine_mode wanted_mode
        !          1665:                  = insn_operand_mode[(int) CODE_FOR_insv][0];
        !          1666:                enum machine_mode is_mode = GET_MODE (tem);
        !          1667:                int width = INTVAL (XEXP (outerdest, 1));
        !          1668:                int pos = INTVAL (XEXP (outerdest, 2));
        !          1669: 
        !          1670:                /* If we have a narrower mode, we can do something.  */
        !          1671:                if (GET_MODE_SIZE (wanted_mode) < GET_MODE_SIZE (is_mode))
        !          1672:                  {
        !          1673:                    int offset = pos / BITS_PER_UNIT;
        !          1674:                    rtx old_pos = XEXP (outerdest, 2);
        !          1675:                    rtx newmem;
        !          1676: 
        !          1677: #if BYTES_BIG_ENDIAN != BITS_BIG_ENDIAN
        !          1678:                    offset = (GET_MODE_SIZE (is_mode)
        !          1679:                              - GET_MODE_SIZE (wanted_mode) - offset);
        !          1680: #endif
        !          1681: 
        !          1682:                    pos %= GET_MODE_BITSIZE (wanted_mode);
        !          1683: 
        !          1684:                    newmem = gen_rtx (MEM, wanted_mode,
        !          1685:                                      plus_constant (XEXP (tem, 0), offset));
        !          1686:                    RTX_UNCHANGING_P (newmem) = RTX_UNCHANGING_P (tem);
        !          1687:                    MEM_VOLATILE_P (newmem) = MEM_VOLATILE_P (tem);
        !          1688:                    MEM_IN_STRUCT_P (newmem) = MEM_IN_STRUCT_P (tem);
        !          1689: 
        !          1690:                    /* Make the change and see if the insn remains valid.  */
        !          1691:                    INSN_CODE (insn) = -1;
        !          1692:                    XEXP (outerdest, 0) = newmem;
        !          1693:                    XEXP (outerdest, 2) = GEN_INT (pos);
        !          1694:                    
        !          1695:                    if (recog_memoized (insn) >= 0)
        !          1696:                      return;
        !          1697:                    
        !          1698:                    /* Otherwise, restore old position.  XEXP (x, 0) will be
        !          1699:                       restored later.  */
        !          1700:                    XEXP (outerdest, 2) = old_pos;
        !          1701:                  }
        !          1702:              }
        !          1703: 
        !          1704:            /* If we get here, the bit-field store doesn't allow memory
        !          1705:               or isn't located at a constant position.  Load the value into
        !          1706:               a register, do the store, and put it back into memory.  */
        !          1707: 
        !          1708:            tem1 = gen_reg_rtx (GET_MODE (tem));
        !          1709:            emit_insn_before (gen_move_insn (tem1, tem), insn);
        !          1710:            emit_insn_after (gen_move_insn (tem, tem1), insn);
        !          1711:            XEXP (outerdest, 0) = tem1;
        !          1712:            return;
        !          1713:          }
        !          1714: #endif
        !          1715: 
        !          1716:        /* STRICT_LOW_PART is a no-op on memory references
        !          1717:           and it can cause combinations to be unrecognizable,
        !          1718:           so eliminate it.  */
        !          1719: 
        !          1720:        if (dest == var && GET_CODE (SET_DEST (x)) == STRICT_LOW_PART)
        !          1721:          SET_DEST (x) = XEXP (SET_DEST (x), 0);
        !          1722: 
        !          1723:        /* A valid insn to copy VAR into or out of a register
        !          1724:           must be left alone, to avoid an infinite loop here.
        !          1725:           If the reference to VAR is by a subreg, fix that up,
        !          1726:           since SUBREG is not valid for a memref.
        !          1727:           Also fix up the address of the stack slot.
        !          1728: 
        !          1729:           Note that we must not try to recognize the insn until
        !          1730:           after we know that we have valid addresses and no
        !          1731:           (subreg (mem ...) ...) constructs, since these interfere
        !          1732:           with determining the validity of the insn.  */
        !          1733: 
        !          1734:        if ((SET_SRC (x) == var
        !          1735:             || (GET_CODE (SET_SRC (x)) == SUBREG
        !          1736:                 && SUBREG_REG (SET_SRC (x)) == var))
        !          1737:            && (GET_CODE (SET_DEST (x)) == REG
        !          1738:                || (GET_CODE (SET_DEST (x)) == SUBREG
        !          1739:                    && GET_CODE (SUBREG_REG (SET_DEST (x))) == REG))
        !          1740:            && x == single_set (PATTERN (insn)))
        !          1741:          {
        !          1742:            rtx pat;
        !          1743: 
        !          1744:            replacement = find_fixup_replacement (replacements, SET_SRC (x));
        !          1745:            if (replacement->new)
        !          1746:              SET_SRC (x) = replacement->new;
        !          1747:            else if (GET_CODE (SET_SRC (x)) == SUBREG)
        !          1748:              SET_SRC (x) = replacement->new
        !          1749:                = fixup_memory_subreg (SET_SRC (x), insn, 0);
        !          1750:            else
        !          1751:              SET_SRC (x) = replacement->new
        !          1752:                = fixup_stack_1 (SET_SRC (x), insn);
        !          1753: 
        !          1754:            if (recog_memoized (insn) >= 0)
        !          1755:              return;
        !          1756: 
        !          1757:            /* INSN is not valid, but we know that we want to
        !          1758:               copy SET_SRC (x) to SET_DEST (x) in some way.  So
        !          1759:               we generate the move and see whether it requires more
        !          1760:               than one insn.  If it does, we emit those insns and
        !          1761:               delete INSN.  Otherwise, we an just replace the pattern 
        !          1762:               of INSN; we have already verified above that INSN has
        !          1763:               no other function that to do X.  */
        !          1764: 
        !          1765:            pat = gen_move_insn (SET_DEST (x), SET_SRC (x));
        !          1766:            if (GET_CODE (pat) == SEQUENCE)
        !          1767:              {
        !          1768:                emit_insn_after (pat, insn);
        !          1769:                PUT_CODE (insn, NOTE);
        !          1770:                NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
        !          1771:                NOTE_SOURCE_FILE (insn) = 0;
        !          1772:              }
        !          1773:            else
        !          1774:              PATTERN (insn) = pat;
        !          1775: 
        !          1776:            return;
        !          1777:          }
        !          1778: 
        !          1779:        if ((SET_DEST (x) == var
        !          1780:             || (GET_CODE (SET_DEST (x)) == SUBREG
        !          1781:                 && SUBREG_REG (SET_DEST (x)) == var))
        !          1782:            && (GET_CODE (SET_SRC (x)) == REG
        !          1783:                || (GET_CODE (SET_SRC (x)) == SUBREG
        !          1784:                    && GET_CODE (SUBREG_REG (SET_SRC (x))) == REG))
        !          1785:            && x == single_set (PATTERN (insn)))
        !          1786:          {
        !          1787:            rtx pat;
        !          1788: 
        !          1789:            if (GET_CODE (SET_DEST (x)) == SUBREG)
        !          1790:              SET_DEST (x) = fixup_memory_subreg (SET_DEST (x), insn, 0);
        !          1791:            else
        !          1792:              SET_DEST (x) = fixup_stack_1 (SET_DEST (x), insn);
        !          1793: 
        !          1794:            if (recog_memoized (insn) >= 0)
        !          1795:              return;
        !          1796: 
        !          1797:            pat = gen_move_insn (SET_DEST (x), SET_SRC (x));
        !          1798:            if (GET_CODE (pat) == SEQUENCE)
        !          1799:              {
        !          1800:                emit_insn_after (pat, insn);
        !          1801:                PUT_CODE (insn, NOTE);
        !          1802:                NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
        !          1803:                NOTE_SOURCE_FILE (insn) = 0;
        !          1804:              }
        !          1805:            else
        !          1806:              PATTERN (insn) = pat;
        !          1807: 
        !          1808:            return;
        !          1809:          }
        !          1810: 
        !          1811:        /* Otherwise, storing into VAR must be handled specially
        !          1812:           by storing into a temporary and copying that into VAR
        !          1813:           with a new insn after this one.  Note that this case
        !          1814:           will be used when storing into a promoted scalar since
        !          1815:           the insn will now have different modes on the input
        !          1816:           and output and hence will be invalid (except for the case
        !          1817:           of setting it to a constant, which does not need any
        !          1818:           change if it is valid).  We generate extra code in that case,
        !          1819:           but combine.c will eliminate it.  */
        !          1820: 
        !          1821:        if (dest == var)
        !          1822:          {
        !          1823:            rtx temp;
        !          1824:            rtx fixeddest = SET_DEST (x);
        !          1825: 
        !          1826:            /* STRICT_LOW_PART can be discarded, around a MEM.  */
        !          1827:            if (GET_CODE (fixeddest) == STRICT_LOW_PART)
        !          1828:              fixeddest = XEXP (fixeddest, 0);
        !          1829:            /* Convert (SUBREG (MEM)) to a MEM in a changed mode.  */
        !          1830:            if (GET_CODE (fixeddest) == SUBREG)
        !          1831:              fixeddest = fixup_memory_subreg (fixeddest, insn, 0);
        !          1832:            else
        !          1833:              fixeddest = fixup_stack_1 (fixeddest, insn);
        !          1834: 
        !          1835:            temp = gen_reg_rtx (GET_MODE (SET_SRC (x)) == VOIDmode
        !          1836:                                ? GET_MODE (fixeddest)
        !          1837:                                : GET_MODE (SET_SRC (x)));
        !          1838: 
        !          1839:            emit_insn_after (gen_move_insn (fixeddest,
        !          1840:                                            gen_lowpart (GET_MODE (fixeddest),
        !          1841:                                                         temp)),
        !          1842:                             insn);
        !          1843: 
        !          1844:            SET_DEST (x) = temp;
        !          1845:          }
        !          1846:       }
        !          1847:     }
        !          1848: 
        !          1849:   /* Nothing special about this RTX; fix its operands.  */
        !          1850: 
        !          1851:   fmt = GET_RTX_FORMAT (code);
        !          1852:   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
        !          1853:     {
        !          1854:       if (fmt[i] == 'e')
        !          1855:        fixup_var_refs_1 (var, promoted_mode, &XEXP (x, i), insn, replacements);
        !          1856:       if (fmt[i] == 'E')
        !          1857:        {
        !          1858:          register int j;
        !          1859:          for (j = 0; j < XVECLEN (x, i); j++)
        !          1860:            fixup_var_refs_1 (var, promoted_mode, &XVECEXP (x, i, j),
        !          1861:                              insn, replacements);
        !          1862:        }
        !          1863:     }
        !          1864: }
        !          1865: 
        !          1866: /* Given X, an rtx of the form (SUBREG:m1 (MEM:m2 addr)),
        !          1867:    return an rtx (MEM:m1 newaddr) which is equivalent.
        !          1868:    If any insns must be emitted to compute NEWADDR, put them before INSN.
        !          1869: 
        !          1870:    UNCRITICAL nonzero means accept paradoxical subregs.
        !          1871:    This is used for subregs found inside of ZERO_EXTRACTs and in REG_NOTES. */
        !          1872: 
        !          1873: static rtx
        !          1874: fixup_memory_subreg (x, insn, uncritical)
        !          1875:      rtx x;
        !          1876:      rtx insn;
        !          1877:      int uncritical;
        !          1878: {
        !          1879:   int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
        !          1880:   rtx addr = XEXP (SUBREG_REG (x), 0);
        !          1881:   enum machine_mode mode = GET_MODE (x);
        !          1882:   rtx saved, result;
        !          1883: 
        !          1884:   /* Paradoxical SUBREGs are usually invalid during RTL generation.  */
        !          1885:   if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))
        !          1886:       && ! uncritical)
        !          1887:     abort ();
        !          1888: 
        !          1889: #if BYTES_BIG_ENDIAN
        !          1890:   offset += (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
        !          1891:             - MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode)));
        !          1892: #endif
        !          1893:   addr = plus_constant (addr, offset);
        !          1894:   if (!flag_force_addr && memory_address_p (mode, addr))
        !          1895:     /* Shortcut if no insns need be emitted.  */
        !          1896:     return change_address (SUBREG_REG (x), mode, addr);
        !          1897:   start_sequence ();
        !          1898:   result = change_address (SUBREG_REG (x), mode, addr);
        !          1899:   emit_insn_before (gen_sequence (), insn);
        !          1900:   end_sequence ();
        !          1901:   return result;
        !          1902: }
        !          1903: 
        !          1904: /* Do fixup_memory_subreg on all (SUBREG (MEM ...) ...) contained in X.
        !          1905:    Replace subexpressions of X in place.
        !          1906:    If X itself is a (SUBREG (MEM ...) ...), return the replacement expression.
        !          1907:    Otherwise return X, with its contents possibly altered.
        !          1908: 
        !          1909:    If any insns must be emitted to compute NEWADDR, put them before INSN. 
        !          1910: 
        !          1911:    UNCRITICAL is as in fixup_memory_subreg.  */
        !          1912: 
        !          1913: static rtx
        !          1914: walk_fixup_memory_subreg (x, insn, uncritical)
        !          1915:      register rtx x;
        !          1916:      rtx insn;
        !          1917:      int uncritical;
        !          1918: {
        !          1919:   register enum rtx_code code;
        !          1920:   register char *fmt;
        !          1921:   register int i;
        !          1922: 
        !          1923:   if (x == 0)
        !          1924:     return 0;
        !          1925: 
        !          1926:   code = GET_CODE (x);
        !          1927: 
        !          1928:   if (code == SUBREG && GET_CODE (SUBREG_REG (x)) == MEM)
        !          1929:     return fixup_memory_subreg (x, insn, uncritical);
        !          1930: 
        !          1931:   /* Nothing special about this RTX; fix its operands.  */
        !          1932: 
        !          1933:   fmt = GET_RTX_FORMAT (code);
        !          1934:   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
        !          1935:     {
        !          1936:       if (fmt[i] == 'e')
        !          1937:        XEXP (x, i) = walk_fixup_memory_subreg (XEXP (x, i), insn, uncritical);
        !          1938:       if (fmt[i] == 'E')
        !          1939:        {
        !          1940:          register int j;
        !          1941:          for (j = 0; j < XVECLEN (x, i); j++)
        !          1942:            XVECEXP (x, i, j)
        !          1943:              = walk_fixup_memory_subreg (XVECEXP (x, i, j), insn, uncritical);
        !          1944:        }
        !          1945:     }
        !          1946:   return x;
        !          1947: }
        !          1948: 
        !          1949: #if 0
        !          1950: /* Fix up any references to stack slots that are invalid memory addresses
        !          1951:    because they exceed the maximum range of a displacement.  */
        !          1952: 
        !          1953: void
        !          1954: fixup_stack_slots ()
        !          1955: {
        !          1956:   register rtx insn;
        !          1957: 
        !          1958:   /* Did we generate a stack slot that is out of range
        !          1959:      or otherwise has an invalid address?  */
        !          1960:   if (invalid_stack_slot)
        !          1961:     {
        !          1962:       /* Yes.  Must scan all insns for stack-refs that exceed the limit.  */
        !          1963:       for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
        !          1964:        if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN
        !          1965:            || GET_CODE (insn) == JUMP_INSN)
        !          1966:          fixup_stack_1 (PATTERN (insn), insn);
        !          1967:     }
        !          1968: }
        !          1969: #endif
        !          1970: 
        !          1971: /* For each memory ref within X, if it refers to a stack slot
        !          1972:    with an out of range displacement, put the address in a temp register
        !          1973:    (emitting new insns before INSN to load these registers)
        !          1974:    and alter the memory ref to use that register.
        !          1975:    Replace each such MEM rtx with a copy, to avoid clobberage.  */
        !          1976: 
        !          1977: static rtx
        !          1978: fixup_stack_1 (x, insn)
        !          1979:      rtx x;
        !          1980:      rtx insn;
        !          1981: {
        !          1982:   register int i;
        !          1983:   register RTX_CODE code = GET_CODE (x);
        !          1984:   register char *fmt;
        !          1985: 
        !          1986:   if (code == MEM)
        !          1987:     {
        !          1988:       register rtx ad = XEXP (x, 0);
        !          1989:       /* If we have address of a stack slot but it's not valid
        !          1990:         (displacement is too large), compute the sum in a register.  */
        !          1991:       if (GET_CODE (ad) == PLUS
        !          1992:          && GET_CODE (XEXP (ad, 0)) == REG
        !          1993:          && ((REGNO (XEXP (ad, 0)) >= FIRST_VIRTUAL_REGISTER
        !          1994:               && REGNO (XEXP (ad, 0)) <= LAST_VIRTUAL_REGISTER)
        !          1995:              || XEXP (ad, 0) == current_function_internal_arg_pointer)
        !          1996:          && GET_CODE (XEXP (ad, 1)) == CONST_INT)
        !          1997:        {
        !          1998:          rtx temp, seq;
        !          1999:          if (memory_address_p (GET_MODE (x), ad))
        !          2000:            return x;
        !          2001: 
        !          2002:          start_sequence ();
        !          2003:          temp = copy_to_reg (ad);
        !          2004:          seq = gen_sequence ();
        !          2005:          end_sequence ();
        !          2006:          emit_insn_before (seq, insn);
        !          2007:          return change_address (x, VOIDmode, temp);
        !          2008:        }
        !          2009:       return x;
        !          2010:     }
        !          2011: 
        !          2012:   fmt = GET_RTX_FORMAT (code);
        !          2013:   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
        !          2014:     {
        !          2015:       if (fmt[i] == 'e')
        !          2016:        XEXP (x, i) = fixup_stack_1 (XEXP (x, i), insn);
        !          2017:       if (fmt[i] == 'E')
        !          2018:        {
        !          2019:          register int j;
        !          2020:          for (j = 0; j < XVECLEN (x, i); j++)
        !          2021:            XVECEXP (x, i, j) = fixup_stack_1 (XVECEXP (x, i, j), insn);
        !          2022:        }
        !          2023:     }
        !          2024:   return x;
        !          2025: }
        !          2026: 
        !          2027: /* Optimization: a bit-field instruction whose field
        !          2028:    happens to be a byte or halfword in memory
        !          2029:    can be changed to a move instruction.
        !          2030: 
        !          2031:    We call here when INSN is an insn to examine or store into a bit-field.
        !          2032:    BODY is the SET-rtx to be altered.
        !          2033: 
        !          2034:    EQUIV_MEM is the table `reg_equiv_mem' if that is available; else 0.
        !          2035:    (Currently this is called only from function.c, and EQUIV_MEM
        !          2036:    is always 0.)  */
        !          2037: 
        !          2038: static void
        !          2039: optimize_bit_field (body, insn, equiv_mem)
        !          2040:      rtx body;
        !          2041:      rtx insn;
        !          2042:      rtx *equiv_mem;
        !          2043: {
        !          2044:   register rtx bitfield;
        !          2045:   int destflag;
        !          2046:   rtx seq = 0;
        !          2047:   enum machine_mode mode;
        !          2048: 
        !          2049:   if (GET_CODE (SET_DEST (body)) == SIGN_EXTRACT
        !          2050:       || GET_CODE (SET_DEST (body)) == ZERO_EXTRACT)
        !          2051:     bitfield = SET_DEST (body), destflag = 1;
        !          2052:   else
        !          2053:     bitfield = SET_SRC (body), destflag = 0;
        !          2054: 
        !          2055:   /* First check that the field being stored has constant size and position
        !          2056:      and is in fact a byte or halfword suitably aligned.  */
        !          2057: 
        !          2058:   if (GET_CODE (XEXP (bitfield, 1)) == CONST_INT
        !          2059:       && GET_CODE (XEXP (bitfield, 2)) == CONST_INT
        !          2060:       && ((mode = mode_for_size (INTVAL (XEXP (bitfield, 1)), MODE_INT, 1))
        !          2061:          != BLKmode)
        !          2062:       && INTVAL (XEXP (bitfield, 2)) % INTVAL (XEXP (bitfield, 1)) == 0)
        !          2063:     {
        !          2064:       register rtx memref = 0;
        !          2065: 
        !          2066:       /* Now check that the containing word is memory, not a register,
        !          2067:         and that it is safe to change the machine mode.  */
        !          2068: 
        !          2069:       if (GET_CODE (XEXP (bitfield, 0)) == MEM)
        !          2070:        memref = XEXP (bitfield, 0);
        !          2071:       else if (GET_CODE (XEXP (bitfield, 0)) == REG
        !          2072:               && equiv_mem != 0)
        !          2073:        memref = equiv_mem[REGNO (XEXP (bitfield, 0))];
        !          2074:       else if (GET_CODE (XEXP (bitfield, 0)) == SUBREG
        !          2075:               && GET_CODE (SUBREG_REG (XEXP (bitfield, 0))) == MEM)
        !          2076:        memref = SUBREG_REG (XEXP (bitfield, 0));
        !          2077:       else if (GET_CODE (XEXP (bitfield, 0)) == SUBREG
        !          2078:               && equiv_mem != 0
        !          2079:               && GET_CODE (SUBREG_REG (XEXP (bitfield, 0))) == REG)
        !          2080:        memref = equiv_mem[REGNO (SUBREG_REG (XEXP (bitfield, 0)))];
        !          2081: 
        !          2082:       if (memref
        !          2083:          && ! mode_dependent_address_p (XEXP (memref, 0))
        !          2084:          && ! MEM_VOLATILE_P (memref))
        !          2085:        {
        !          2086:          /* Now adjust the address, first for any subreg'ing
        !          2087:             that we are now getting rid of,
        !          2088:             and then for which byte of the word is wanted.  */
        !          2089: 
        !          2090:          register int offset = INTVAL (XEXP (bitfield, 2));
        !          2091:          /* Adjust OFFSET to count bits from low-address byte.  */
        !          2092: #if BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN
        !          2093:          offset = (GET_MODE_BITSIZE (GET_MODE (XEXP (bitfield, 0)))
        !          2094:                    - offset - INTVAL (XEXP (bitfield, 1)));
        !          2095: #endif
        !          2096:          /* Adjust OFFSET to count bytes from low-address byte.  */
        !          2097:          offset /= BITS_PER_UNIT;
        !          2098:          if (GET_CODE (XEXP (bitfield, 0)) == SUBREG)
        !          2099:            {
        !          2100:              offset += SUBREG_WORD (XEXP (bitfield, 0)) * UNITS_PER_WORD;
        !          2101: #if BYTES_BIG_ENDIAN
        !          2102:              offset -= (MIN (UNITS_PER_WORD,
        !          2103:                              GET_MODE_SIZE (GET_MODE (XEXP (bitfield, 0))))
        !          2104:                         - MIN (UNITS_PER_WORD,
        !          2105:                                GET_MODE_SIZE (GET_MODE (memref))));
        !          2106: #endif
        !          2107:            }
        !          2108: 
        !          2109:          memref = change_address (memref, mode, 
        !          2110:                                   plus_constant (XEXP (memref, 0), offset));
        !          2111: 
        !          2112:          /* Store this memory reference where
        !          2113:             we found the bit field reference.  */
        !          2114: 
        !          2115:          if (destflag)
        !          2116:            {
        !          2117:              validate_change (insn, &SET_DEST (body), memref, 1);
        !          2118:              if (! CONSTANT_ADDRESS_P (SET_SRC (body)))
        !          2119:                {
        !          2120:                  rtx src = SET_SRC (body);
        !          2121:                  while (GET_CODE (src) == SUBREG
        !          2122:                         && SUBREG_WORD (src) == 0)
        !          2123:                    src = SUBREG_REG (src);
        !          2124:                  if (GET_MODE (src) != GET_MODE (memref))
        !          2125:                    src = gen_lowpart (GET_MODE (memref), SET_SRC (body));
        !          2126:                  validate_change (insn, &SET_SRC (body), src, 1);
        !          2127:                }
        !          2128:              else if (GET_MODE (SET_SRC (body)) != VOIDmode
        !          2129:                       && GET_MODE (SET_SRC (body)) != GET_MODE (memref))
        !          2130:                /* This shouldn't happen because anything that didn't have
        !          2131:                   one of these modes should have got converted explicitly
        !          2132:                   and then referenced through a subreg.
        !          2133:                   This is so because the original bit-field was
        !          2134:                   handled by agg_mode and so its tree structure had
        !          2135:                   the same mode that memref now has.  */
        !          2136:                abort ();
        !          2137:            }
        !          2138:          else
        !          2139:            {
        !          2140:              rtx dest = SET_DEST (body);
        !          2141: 
        !          2142:              while (GET_CODE (dest) == SUBREG
        !          2143:                     && SUBREG_WORD (dest) == 0)
        !          2144:                dest = SUBREG_REG (dest);
        !          2145: 
        !          2146:              validate_change (insn, &SET_DEST (body), dest, 1);
        !          2147: 
        !          2148:              if (GET_MODE (dest) == GET_MODE (memref))
        !          2149:                validate_change (insn, &SET_SRC (body), memref, 1);
        !          2150:              else
        !          2151:                {
        !          2152:                  /* Convert the mem ref to the destination mode.  */
        !          2153:                  rtx newreg = gen_reg_rtx (GET_MODE (dest));
        !          2154: 
        !          2155:                  start_sequence ();
        !          2156:                  convert_move (newreg, memref,
        !          2157:                                GET_CODE (SET_SRC (body)) == ZERO_EXTRACT);
        !          2158:                  seq = get_insns ();
        !          2159:                  end_sequence ();
        !          2160: 
        !          2161:                  validate_change (insn, &SET_SRC (body), newreg, 1);
        !          2162:                }
        !          2163:            }
        !          2164: 
        !          2165:          /* See if we can convert this extraction or insertion into
        !          2166:             a simple move insn.  We might not be able to do so if this
        !          2167:             was, for example, part of a PARALLEL.
        !          2168: 
        !          2169:             If we succeed, write out any needed conversions.  If we fail,
        !          2170:             it is hard to guess why we failed, so don't do anything
        !          2171:             special; just let the optimization be suppressed.  */
        !          2172: 
        !          2173:          if (apply_change_group () && seq)
        !          2174:            emit_insns_before (seq, insn);
        !          2175:        }
        !          2176:     }
        !          2177: }
        !          2178: 
        !          2179: /* These routines are responsible for converting virtual register references
        !          2180:    to the actual hard register references once RTL generation is complete.
        !          2181: 
        !          2182:    The following four variables are used for communication between the
        !          2183:    routines.  They contain the offsets of the virtual registers from their
        !          2184:    respective hard registers.  */
        !          2185: 
        !          2186: static int in_arg_offset;
        !          2187: static int var_offset;
        !          2188: static int dynamic_offset;
        !          2189: static int out_arg_offset;
        !          2190: 
        !          2191: /* In most machines, the stack pointer register is equivalent to the bottom
        !          2192:    of the stack.  */
        !          2193: 
        !          2194: #ifndef STACK_POINTER_OFFSET
        !          2195: #define STACK_POINTER_OFFSET   0
        !          2196: #endif
        !          2197: 
        !          2198: /* If not defined, pick an appropriate default for the offset of dynamically
        !          2199:    allocated memory depending on the value of ACCUMULATE_OUTGOING_ARGS,
        !          2200:    REG_PARM_STACK_SPACE, and OUTGOING_REG_PARM_STACK_SPACE.  */
        !          2201: 
        !          2202: #ifndef STACK_DYNAMIC_OFFSET
        !          2203: 
        !          2204: #ifdef ACCUMULATE_OUTGOING_ARGS
        !          2205: /* The bottom of the stack points to the actual arguments.  If
        !          2206:    REG_PARM_STACK_SPACE is defined, this includes the space for the register
        !          2207:    parameters.  However, if OUTGOING_REG_PARM_STACK space is not defined,
        !          2208:    stack space for register parameters is not pushed by the caller, but 
        !          2209:    rather part of the fixed stack areas and hence not included in
        !          2210:    `current_function_outgoing_args_size'.  Nevertheless, we must allow
        !          2211:    for it when allocating stack dynamic objects.  */
        !          2212: 
        !          2213: #if defined(REG_PARM_STACK_SPACE) && ! defined(OUTGOING_REG_PARM_STACK_SPACE)
        !          2214: #define STACK_DYNAMIC_OFFSET(FNDECL)   \
        !          2215: (current_function_outgoing_args_size   \
        !          2216:  + REG_PARM_STACK_SPACE (FNDECL) + (STACK_POINTER_OFFSET))
        !          2217: 
        !          2218: #else
        !          2219: #define STACK_DYNAMIC_OFFSET(FNDECL)   \
        !          2220: (current_function_outgoing_args_size + (STACK_POINTER_OFFSET))
        !          2221: #endif
        !          2222: 
        !          2223: #else
        !          2224: #define STACK_DYNAMIC_OFFSET(FNDECL) STACK_POINTER_OFFSET
        !          2225: #endif
        !          2226: #endif
        !          2227: 
        !          2228: /* Pass through the INSNS of function FNDECL and convert virtual register
        !          2229:    references to hard register references.  */
        !          2230: 
        !          2231: void
        !          2232: instantiate_virtual_regs (fndecl, insns)
        !          2233:      tree fndecl;
        !          2234:      rtx insns;
        !          2235: {
        !          2236:   rtx insn;
        !          2237: 
        !          2238:   /* Compute the offsets to use for this function.  */
        !          2239:   in_arg_offset = FIRST_PARM_OFFSET (fndecl);
        !          2240:   var_offset = STARTING_FRAME_OFFSET;
        !          2241:   dynamic_offset = STACK_DYNAMIC_OFFSET (fndecl);
        !          2242:   out_arg_offset = STACK_POINTER_OFFSET;
        !          2243: 
        !          2244:   /* Scan all variables and parameters of this function.  For each that is
        !          2245:      in memory, instantiate all virtual registers if the result is a valid
        !          2246:      address.  If not, we do it later.  That will handle most uses of virtual
        !          2247:      regs on many machines.  */
        !          2248:   instantiate_decls (fndecl, 1);
        !          2249: 
        !          2250:   /* Initialize recognition, indicating that volatile is OK.  */
        !          2251:   init_recog ();
        !          2252: 
        !          2253:   /* Scan through all the insns, instantiating every virtual register still
        !          2254:      present.  */
        !          2255:   for (insn = insns; insn; insn = NEXT_INSN (insn))
        !          2256:     if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
        !          2257:        || GET_CODE (insn) == CALL_INSN)
        !          2258:       {
        !          2259:        instantiate_virtual_regs_1 (&PATTERN (insn), insn, 1);
        !          2260:        instantiate_virtual_regs_1 (&REG_NOTES (insn), NULL_RTX, 0);
        !          2261:       }
        !          2262: 
        !          2263:   /* Now instantiate the remaining register equivalences for debugging info.
        !          2264:      These will not be valid addresses.  */
        !          2265:   instantiate_decls (fndecl, 0);
        !          2266: 
        !          2267:   /* Indicate that, from now on, assign_stack_local should use
        !          2268:      frame_pointer_rtx.  */
        !          2269:   virtuals_instantiated = 1;
        !          2270: }
        !          2271: 
        !          2272: /* Scan all decls in FNDECL (both variables and parameters) and instantiate
        !          2273:    all virtual registers in their DECL_RTL's.
        !          2274: 
        !          2275:    If VALID_ONLY, do this only if the resulting address is still valid.
        !          2276:    Otherwise, always do it.  */
        !          2277: 
        !          2278: static void
        !          2279: instantiate_decls (fndecl, valid_only)
        !          2280:      tree fndecl;
        !          2281:      int valid_only;
        !          2282: {
        !          2283:   tree decl;
        !          2284: 
        !          2285:   if (DECL_INLINE (fndecl))
        !          2286:     /* When compiling an inline function, the obstack used for
        !          2287:        rtl allocation is the maybepermanent_obstack.  Calling
        !          2288:        `resume_temporary_allocation' switches us back to that
        !          2289:        obstack while we process this function's parameters.  */
        !          2290:     resume_temporary_allocation ();
        !          2291: 
        !          2292:   /* Process all parameters of the function.  */
        !          2293:   for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl))
        !          2294:     {
        !          2295:       instantiate_decl (DECL_RTL (decl), int_size_in_bytes (TREE_TYPE (decl)),
        !          2296:                        valid_only);    
        !          2297:       instantiate_decl (DECL_INCOMING_RTL (decl),
        !          2298:                        int_size_in_bytes (TREE_TYPE (decl)), valid_only);
        !          2299:     }
        !          2300: 
        !          2301:   /* Now process all variables defined in the function or its subblocks. */
        !          2302:   instantiate_decls_1 (DECL_INITIAL (fndecl), valid_only);
        !          2303: 
        !          2304:   if (DECL_INLINE (fndecl))
        !          2305:     {
        !          2306:       /* Save all rtl allocated for this function by raising the
        !          2307:         high-water mark on the maybepermanent_obstack.  */
        !          2308:       preserve_data ();
        !          2309:       /* All further rtl allocation is now done in the current_obstack.  */
        !          2310:       rtl_in_current_obstack ();
        !          2311:     }
        !          2312: }
        !          2313: 
        !          2314: /* Subroutine of instantiate_decls: Process all decls in the given
        !          2315:    BLOCK node and all its subblocks.  */
        !          2316: 
        !          2317: static void
        !          2318: instantiate_decls_1 (let, valid_only)
        !          2319:      tree let;
        !          2320:      int valid_only;
        !          2321: {
        !          2322:   tree t;
        !          2323: 
        !          2324:   for (t = BLOCK_VARS (let); t; t = TREE_CHAIN (t))
        !          2325:     instantiate_decl (DECL_RTL (t), int_size_in_bytes (TREE_TYPE (t)),
        !          2326:                      valid_only);
        !          2327: 
        !          2328:   /* Process all subblocks.  */
        !          2329:   for (t = BLOCK_SUBBLOCKS (let); t; t = TREE_CHAIN (t))
        !          2330:     instantiate_decls_1 (t, valid_only);
        !          2331: }
        !          2332: 
        !          2333: /* Subroutine of the preceding procedures: Given RTL representing a
        !          2334:    decl and the size of the object, do any instantiation required.
        !          2335: 
        !          2336:    If VALID_ONLY is non-zero, it means that the RTL should only be
        !          2337:    changed if the new address is valid.  */
        !          2338: 
        !          2339: static void
        !          2340: instantiate_decl (x, size, valid_only)
        !          2341:      rtx x;
        !          2342:      int size;
        !          2343:      int valid_only;
        !          2344: {
        !          2345:   enum machine_mode mode;
        !          2346:   rtx addr;
        !          2347: 
        !          2348:   /* If this is not a MEM, no need to do anything.  Similarly if the
        !          2349:      address is a constant or a register that is not a virtual register.  */
        !          2350: 
        !          2351:   if (x == 0 || GET_CODE (x) != MEM)
        !          2352:     return;
        !          2353: 
        !          2354:   addr = XEXP (x, 0);
        !          2355:   if (CONSTANT_P (addr)
        !          2356:       || (GET_CODE (addr) == REG
        !          2357:          && (REGNO (addr) < FIRST_VIRTUAL_REGISTER
        !          2358:              || REGNO (addr) > LAST_VIRTUAL_REGISTER)))
        !          2359:     return;
        !          2360: 
        !          2361:   /* If we should only do this if the address is valid, copy the address.
        !          2362:      We need to do this so we can undo any changes that might make the
        !          2363:      address invalid.  This copy is unfortunate, but probably can't be
        !          2364:      avoided.  */
        !          2365: 
        !          2366:   if (valid_only)
        !          2367:     addr = copy_rtx (addr);
        !          2368: 
        !          2369:   instantiate_virtual_regs_1 (&addr, NULL_RTX, 0);
        !          2370: 
        !          2371:   if (! valid_only)
        !          2372:     return;
        !          2373: 
        !          2374:   /* Now verify that the resulting address is valid for every integer or
        !          2375:      floating-point mode up to and including SIZE bytes long.  We do this
        !          2376:      since the object might be accessed in any mode and frame addresses
        !          2377:      are shared.  */
        !          2378: 
        !          2379:   for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
        !          2380:        mode != VOIDmode && GET_MODE_SIZE (mode) <= size;
        !          2381:        mode = GET_MODE_WIDER_MODE (mode))
        !          2382:     if (! memory_address_p (mode, addr))
        !          2383:       return;
        !          2384: 
        !          2385:   for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
        !          2386:        mode != VOIDmode && GET_MODE_SIZE (mode) <= size;
        !          2387:        mode = GET_MODE_WIDER_MODE (mode))
        !          2388:     if (! memory_address_p (mode, addr))
        !          2389:       return;
        !          2390: 
        !          2391:   /* Otherwise, put back the address, now that we have updated it and we
        !          2392:      know it is valid.  */
        !          2393: 
        !          2394:   XEXP (x, 0) = addr;
        !          2395: }
        !          2396: 
        !          2397: /* Given a pointer to a piece of rtx and an optional pointer to the
        !          2398:    containing object, instantiate any virtual registers present in it.
        !          2399: 
        !          2400:    If EXTRA_INSNS, we always do the replacement and generate
        !          2401:    any extra insns before OBJECT.  If it zero, we do nothing if replacement
        !          2402:    is not valid.
        !          2403: 
        !          2404:    Return 1 if we either had nothing to do or if we were able to do the
        !          2405:    needed replacement.  Return 0 otherwise; we only return zero if 
        !          2406:    EXTRA_INSNS is zero.
        !          2407: 
        !          2408:    We first try some simple transformations to avoid the creation of extra
        !          2409:    pseudos.  */
        !          2410: 
        !          2411: static int
        !          2412: instantiate_virtual_regs_1 (loc, object, extra_insns)
        !          2413:      rtx *loc;
        !          2414:      rtx object;
        !          2415:      int extra_insns;
        !          2416: {
        !          2417:   rtx x;
        !          2418:   RTX_CODE code;
        !          2419:   rtx new = 0;
        !          2420:   int offset;
        !          2421:   rtx temp;
        !          2422:   rtx seq;
        !          2423:   int i, j;
        !          2424:   char *fmt;
        !          2425: 
        !          2426:   /* Re-start here to avoid recursion in common cases.  */
        !          2427:  restart:
        !          2428: 
        !          2429:   x = *loc;
        !          2430:   if (x == 0)
        !          2431:     return 1;
        !          2432: 
        !          2433:   code = GET_CODE (x);
        !          2434: 
        !          2435:   /* Check for some special cases.  */
        !          2436:   switch (code)
        !          2437:     {
        !          2438:     case CONST_INT:
        !          2439:     case CONST_DOUBLE:
        !          2440:     case CONST:
        !          2441:     case SYMBOL_REF:
        !          2442:     case CODE_LABEL:
        !          2443:     case PC:
        !          2444:     case CC0:
        !          2445:     case ASM_INPUT:
        !          2446:     case ADDR_VEC:
        !          2447:     case ADDR_DIFF_VEC:
        !          2448:     case RETURN:
        !          2449:       return 1;
        !          2450: 
        !          2451:     case SET:
        !          2452:       /* We are allowed to set the virtual registers.  This means that
        !          2453:         that the actual register should receive the source minus the
        !          2454:         appropriate offset.  This is used, for example, in the handling
        !          2455:         of non-local gotos.  */
        !          2456:       if (SET_DEST (x) == virtual_incoming_args_rtx)
        !          2457:        new = arg_pointer_rtx, offset = - in_arg_offset;
        !          2458:       else if (SET_DEST (x) == virtual_stack_vars_rtx)
        !          2459:        new = frame_pointer_rtx, offset = - var_offset;
        !          2460:       else if (SET_DEST (x) == virtual_stack_dynamic_rtx)
        !          2461:        new = stack_pointer_rtx, offset = - dynamic_offset;
        !          2462:       else if (SET_DEST (x) == virtual_outgoing_args_rtx)
        !          2463:        new = stack_pointer_rtx, offset = - out_arg_offset;
        !          2464: 
        !          2465:       if (new)
        !          2466:        {
        !          2467:          /* The only valid sources here are PLUS or REG.  Just do
        !          2468:             the simplest possible thing to handle them.  */
        !          2469:          if (GET_CODE (SET_SRC (x)) != REG
        !          2470:              && GET_CODE (SET_SRC (x)) != PLUS)
        !          2471:            abort ();
        !          2472: 
        !          2473:          start_sequence ();
        !          2474:          if (GET_CODE (SET_SRC (x)) != REG)
        !          2475:            temp = force_operand (SET_SRC (x), NULL_RTX);
        !          2476:          else
        !          2477:            temp = SET_SRC (x);
        !          2478:          temp = force_operand (plus_constant (temp, offset), NULL_RTX);
        !          2479:          seq = get_insns ();
        !          2480:          end_sequence ();
        !          2481: 
        !          2482:          emit_insns_before (seq, object);
        !          2483:          SET_DEST (x) = new;
        !          2484: 
        !          2485:          if (!validate_change (object, &SET_SRC (x), temp, 0)
        !          2486:              || ! extra_insns)
        !          2487:            abort ();
        !          2488: 
        !          2489:          return 1;
        !          2490:        }
        !          2491: 
        !          2492:       instantiate_virtual_regs_1 (&SET_DEST (x), object, extra_insns);
        !          2493:       loc = &SET_SRC (x);
        !          2494:       goto restart;
        !          2495: 
        !          2496:     case PLUS:
        !          2497:       /* Handle special case of virtual register plus constant.  */
        !          2498:       if (CONSTANT_P (XEXP (x, 1)))
        !          2499:        {
        !          2500:          rtx old;
        !          2501: 
        !          2502:          /* Check for (plus (plus VIRT foo) (const_int)) first.  */
        !          2503:          if (GET_CODE (XEXP (x, 0)) == PLUS)
        !          2504:            {
        !          2505:              rtx inner = XEXP (XEXP (x, 0), 0);
        !          2506: 
        !          2507:              if (inner == virtual_incoming_args_rtx)
        !          2508:                new = arg_pointer_rtx, offset = in_arg_offset;
        !          2509:              else if (inner == virtual_stack_vars_rtx)
        !          2510:                new = frame_pointer_rtx, offset = var_offset;
        !          2511:              else if (inner == virtual_stack_dynamic_rtx)
        !          2512:                new = stack_pointer_rtx, offset = dynamic_offset;
        !          2513:              else if (inner == virtual_outgoing_args_rtx)
        !          2514:                new = stack_pointer_rtx, offset = out_arg_offset;
        !          2515:              else
        !          2516:                {
        !          2517:                  loc = &XEXP (x, 0);
        !          2518:                  goto restart;
        !          2519:                }
        !          2520: 
        !          2521:              instantiate_virtual_regs_1 (&XEXP (XEXP (x, 0), 1), object,
        !          2522:                                          extra_insns);
        !          2523:              new = gen_rtx (PLUS, Pmode, new, XEXP (XEXP (x, 0), 1));
        !          2524:            }
        !          2525: 
        !          2526:          else if (XEXP (x, 0) == virtual_incoming_args_rtx)
        !          2527:            new = arg_pointer_rtx, offset = in_arg_offset;
        !          2528:          else if (XEXP (x, 0) == virtual_stack_vars_rtx)
        !          2529:            new = frame_pointer_rtx, offset = var_offset;
        !          2530:          else if (XEXP (x, 0) == virtual_stack_dynamic_rtx)
        !          2531:            new = stack_pointer_rtx, offset = dynamic_offset;
        !          2532:          else if (XEXP (x, 0) == virtual_outgoing_args_rtx)
        !          2533:            new = stack_pointer_rtx, offset = out_arg_offset;
        !          2534:          else
        !          2535:            {
        !          2536:              /* We know the second operand is a constant.  Unless the
        !          2537:                 first operand is a REG (which has been already checked),
        !          2538:                 it needs to be checked.  */
        !          2539:              if (GET_CODE (XEXP (x, 0)) != REG)
        !          2540:                {
        !          2541:                  loc = &XEXP (x, 0);
        !          2542:                  goto restart;
        !          2543:                }
        !          2544:              return 1;
        !          2545:            }
        !          2546: 
        !          2547:          old = XEXP (x, 0);
        !          2548:          XEXP (x, 0) = new;
        !          2549:          new = plus_constant (XEXP (x, 1), offset);
        !          2550: 
        !          2551:          /* If the new constant is zero, try to replace the sum with its
        !          2552:             first operand.  */
        !          2553:          if (new == const0_rtx
        !          2554:              && validate_change (object, loc, XEXP (x, 0), 0))
        !          2555:            return 1;
        !          2556: 
        !          2557:          /* Next try to replace constant with new one.  */
        !          2558:          if (!validate_change (object, &XEXP (x, 1), new, 0))
        !          2559:            {
        !          2560:              if (! extra_insns)
        !          2561:                {
        !          2562:                  XEXP (x, 0) = old;
        !          2563:                  return 0;
        !          2564:                }
        !          2565: 
        !          2566:              /* Otherwise copy the new constant into a register and replace
        !          2567:                 constant with that register.  */
        !          2568:              temp = gen_reg_rtx (Pmode);
        !          2569:              if (validate_change (object, &XEXP (x, 1), temp, 0))
        !          2570:                emit_insn_before (gen_move_insn (temp, new), object);
        !          2571:              else
        !          2572:                {
        !          2573:                  /* If that didn't work, replace this expression with a
        !          2574:                     register containing the sum.  */
        !          2575: 
        !          2576:                  new = gen_rtx (PLUS, Pmode, XEXP (x, 0), new);
        !          2577:                  XEXP (x, 0) = old;
        !          2578: 
        !          2579:                  start_sequence ();
        !          2580:                  temp = force_operand (new, NULL_RTX);
        !          2581:                  seq = get_insns ();
        !          2582:                  end_sequence ();
        !          2583: 
        !          2584:                  emit_insns_before (seq, object);
        !          2585:                  if (! validate_change (object, loc, temp, 0)
        !          2586:                      && ! validate_replace_rtx (x, temp, object))
        !          2587:                    abort ();
        !          2588:                }
        !          2589:            }
        !          2590: 
        !          2591:          return 1;
        !          2592:        }
        !          2593: 
        !          2594:       /* Fall through to generic two-operand expression case.  */
        !          2595:     case EXPR_LIST:
        !          2596:     case CALL:
        !          2597:     case COMPARE:
        !          2598:     case MINUS:
        !          2599:     case MULT:
        !          2600:     case DIV:      case UDIV:
        !          2601:     case MOD:      case UMOD:
        !          2602:     case AND:      case IOR:      case XOR:
        !          2603:     case LSHIFT:   case ASHIFT:   case ROTATE:
        !          2604:     case ASHIFTRT: case LSHIFTRT: case ROTATERT:
        !          2605:     case NE:       case EQ:
        !          2606:     case GE:       case GT:       case GEU:    case GTU:
        !          2607:     case LE:       case LT:       case LEU:    case LTU:
        !          2608:       if (XEXP (x, 1) && ! CONSTANT_P (XEXP (x, 1)))
        !          2609:        instantiate_virtual_regs_1 (&XEXP (x, 1), object, extra_insns);
        !          2610:       loc = &XEXP (x, 0);
        !          2611:       goto restart;
        !          2612: 
        !          2613:     case MEM:
        !          2614:       /* Most cases of MEM that convert to valid addresses have already been
        !          2615:         handled by our scan of regno_reg_rtx.  The only special handling we
        !          2616:         need here is to make a copy of the rtx to ensure it isn't being
        !          2617:         shared if we have to change it to a pseudo. 
        !          2618: 
        !          2619:         If the rtx is a simple reference to an address via a virtual register,
        !          2620:         it can potentially be shared.  In such cases, first try to make it
        !          2621:         a valid address, which can also be shared.  Otherwise, copy it and
        !          2622:         proceed normally. 
        !          2623: 
        !          2624:         First check for common cases that need no processing.  These are
        !          2625:         usually due to instantiation already being done on a previous instance
        !          2626:         of a shared rtx.  */
        !          2627: 
        !          2628:       temp = XEXP (x, 0);
        !          2629:       if (CONSTANT_ADDRESS_P (temp)
        !          2630: #if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
        !          2631:          || temp == arg_pointer_rtx
        !          2632: #endif
        !          2633: #if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
        !          2634:          || temp == hard_frame_pointer_rtx
        !          2635: #endif
        !          2636:          || temp == frame_pointer_rtx)
        !          2637:        return 1;
        !          2638: 
        !          2639:       if (GET_CODE (temp) == PLUS
        !          2640:          && CONSTANT_ADDRESS_P (XEXP (temp, 1))
        !          2641:          && (XEXP (temp, 0) == frame_pointer_rtx
        !          2642: #if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
        !          2643:              || XEXP (temp, 0) == hard_frame_pointer_rtx
        !          2644: #endif
        !          2645: #if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
        !          2646:              || XEXP (temp, 0) == arg_pointer_rtx
        !          2647: #endif
        !          2648:              ))
        !          2649:        return 1;
        !          2650: 
        !          2651:       if (temp == virtual_stack_vars_rtx
        !          2652:          || temp == virtual_incoming_args_rtx
        !          2653:          || (GET_CODE (temp) == PLUS
        !          2654:              && CONSTANT_ADDRESS_P (XEXP (temp, 1))
        !          2655:              && (XEXP (temp, 0) == virtual_stack_vars_rtx
        !          2656:                  || XEXP (temp, 0) == virtual_incoming_args_rtx)))
        !          2657:        {
        !          2658:          /* This MEM may be shared.  If the substitution can be done without
        !          2659:             the need to generate new pseudos, we want to do it in place
        !          2660:             so all copies of the shared rtx benefit.  The call below will
        !          2661:             only make substitutions if the resulting address is still
        !          2662:             valid.
        !          2663: 
        !          2664:             Note that we cannot pass X as the object in the recursive call
        !          2665:             since the insn being processed may not allow all valid
        !          2666:             addresses.  However, if we were not passed on object, we can
        !          2667:             only modify X without copying it if X will have a valid
        !          2668:             address.
        !          2669: 
        !          2670:             ??? Also note that this can still lose if OBJECT is an insn that
        !          2671:             has less restrictions on an address that some other insn.
        !          2672:             In that case, we will modify the shared address.  This case
        !          2673:             doesn't seem very likely, though.  */
        !          2674: 
        !          2675:          if (instantiate_virtual_regs_1 (&XEXP (x, 0),
        !          2676:                                          object ? object : x, 0))
        !          2677:            return 1;
        !          2678: 
        !          2679:          /* Otherwise make a copy and process that copy.  We copy the entire
        !          2680:             RTL expression since it might be a PLUS which could also be
        !          2681:             shared.  */
        !          2682:          *loc = x = copy_rtx (x);
        !          2683:        }
        !          2684: 
        !          2685:       /* Fall through to generic unary operation case.  */
        !          2686:     case USE:
        !          2687:     case CLOBBER:
        !          2688:     case SUBREG:
        !          2689:     case STRICT_LOW_PART:
        !          2690:     case NEG:          case NOT:
        !          2691:     case PRE_DEC:      case PRE_INC:      case POST_DEC:    case POST_INC:
        !          2692:     case SIGN_EXTEND:  case ZERO_EXTEND:
        !          2693:     case TRUNCATE:     case FLOAT_EXTEND: case FLOAT_TRUNCATE:
        !          2694:     case FLOAT:        case FIX:
        !          2695:     case UNSIGNED_FIX: case UNSIGNED_FLOAT:
        !          2696:     case ABS:
        !          2697:     case SQRT:
        !          2698:     case FFS:
        !          2699:       /* These case either have just one operand or we know that we need not
        !          2700:         check the rest of the operands.  */
        !          2701:       loc = &XEXP (x, 0);
        !          2702:       goto restart;
        !          2703: 
        !          2704:     case REG:
        !          2705:       /* Try to replace with a PLUS.  If that doesn't work, compute the sum
        !          2706:         in front of this insn and substitute the temporary.  */
        !          2707:       if (x == virtual_incoming_args_rtx)
        !          2708:        new = arg_pointer_rtx, offset = in_arg_offset;
        !          2709:       else if (x == virtual_stack_vars_rtx)
        !          2710:        new = frame_pointer_rtx, offset = var_offset;
        !          2711:       else if (x == virtual_stack_dynamic_rtx)
        !          2712:        new = stack_pointer_rtx, offset = dynamic_offset;
        !          2713:       else if (x == virtual_outgoing_args_rtx)
        !          2714:        new = stack_pointer_rtx, offset = out_arg_offset;
        !          2715: 
        !          2716:       if (new)
        !          2717:        {
        !          2718:          temp = plus_constant (new, offset);
        !          2719:          if (!validate_change (object, loc, temp, 0))
        !          2720:            {
        !          2721:              if (! extra_insns)
        !          2722:                return 0;
        !          2723: 
        !          2724:              start_sequence ();
        !          2725:              temp = force_operand (temp, NULL_RTX);
        !          2726:              seq = get_insns ();
        !          2727:              end_sequence ();
        !          2728: 
        !          2729:              emit_insns_before (seq, object);
        !          2730:              if (! validate_change (object, loc, temp, 0)
        !          2731:                  && ! validate_replace_rtx (x, temp, object))
        !          2732:                abort ();
        !          2733:            }
        !          2734:        }
        !          2735: 
        !          2736:       return 1;
        !          2737:     }
        !          2738: 
        !          2739:   /* Scan all subexpressions.  */
        !          2740:   fmt = GET_RTX_FORMAT (code);
        !          2741:   for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
        !          2742:     if (*fmt == 'e')
        !          2743:       {
        !          2744:        if (!instantiate_virtual_regs_1 (&XEXP (x, i), object, extra_insns))
        !          2745:          return 0;
        !          2746:       }
        !          2747:     else if (*fmt == 'E')
        !          2748:       for (j = 0; j < XVECLEN (x, i); j++)
        !          2749:        if (! instantiate_virtual_regs_1 (&XVECEXP (x, i, j), object,
        !          2750:                                          extra_insns))
        !          2751:          return 0;
        !          2752: 
        !          2753:   return 1;
        !          2754: }
        !          2755: 
        !          2756: /* Optimization: assuming this function does not receive nonlocal gotos,
        !          2757:    delete the handlers for such, as well as the insns to establish
        !          2758:    and disestablish them.  */
        !          2759: 
        !          2760: static void
        !          2761: delete_handlers ()
        !          2762: {
        !          2763:   rtx insn;
        !          2764:   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
        !          2765:     {
        !          2766:       /* Delete the handler by turning off the flag that would
        !          2767:         prevent jump_optimize from deleting it.
        !          2768:         Also permit deletion of the nonlocal labels themselves
        !          2769:         if nothing local refers to them.  */
        !          2770:       if (GET_CODE (insn) == CODE_LABEL)
        !          2771:        LABEL_PRESERVE_P (insn) = 0;
        !          2772:       if (GET_CODE (insn) == INSN
        !          2773:          && ((nonlocal_goto_handler_slot != 0
        !          2774:               && reg_mentioned_p (nonlocal_goto_handler_slot, PATTERN (insn)))
        !          2775:              || (nonlocal_goto_stack_level != 0
        !          2776:                  && reg_mentioned_p (nonlocal_goto_stack_level,
        !          2777:                                      PATTERN (insn)))))
        !          2778:        delete_insn (insn);
        !          2779:     }
        !          2780: }
        !          2781: 
        !          2782: /* Return a list (chain of EXPR_LIST nodes) for the nonlocal labels
        !          2783:    of the current function.  */
        !          2784: 
        !          2785: rtx
        !          2786: nonlocal_label_rtx_list ()
        !          2787: {
        !          2788:   tree t;
        !          2789:   rtx x = 0;
        !          2790: 
        !          2791:   for (t = nonlocal_labels; t; t = TREE_CHAIN (t))
        !          2792:     x = gen_rtx (EXPR_LIST, VOIDmode, label_rtx (TREE_VALUE (t)), x);
        !          2793: 
        !          2794:   return x;
        !          2795: }
        !          2796: 
        !          2797: /* Output a USE for any register use in RTL.
        !          2798:    This is used with -noreg to mark the extent of lifespan
        !          2799:    of any registers used in a user-visible variable's DECL_RTL.  */
        !          2800: 
        !          2801: void
        !          2802: use_variable (rtl)
        !          2803:      rtx rtl;
        !          2804: {
        !          2805:   if (GET_CODE (rtl) == REG)
        !          2806:     /* This is a register variable.  */
        !          2807:     emit_insn (gen_rtx (USE, VOIDmode, rtl));
        !          2808:   else if (GET_CODE (rtl) == MEM
        !          2809:           && GET_CODE (XEXP (rtl, 0)) == REG
        !          2810:           && (REGNO (XEXP (rtl, 0)) < FIRST_VIRTUAL_REGISTER
        !          2811:               || REGNO (XEXP (rtl, 0)) > LAST_VIRTUAL_REGISTER)
        !          2812:           && XEXP (rtl, 0) != current_function_internal_arg_pointer)
        !          2813:     /* This is a variable-sized structure.  */
        !          2814:     emit_insn (gen_rtx (USE, VOIDmode, XEXP (rtl, 0)));
        !          2815: }
        !          2816: 
        !          2817: /* Like use_variable except that it outputs the USEs after INSN
        !          2818:    instead of at the end of the insn-chain.  */
        !          2819: 
        !          2820: void
        !          2821: use_variable_after (rtl, insn)
        !          2822:      rtx rtl, insn;
        !          2823: {
        !          2824:   if (GET_CODE (rtl) == REG)
        !          2825:     /* This is a register variable.  */
        !          2826:     emit_insn_after (gen_rtx (USE, VOIDmode, rtl), insn);
        !          2827:   else if (GET_CODE (rtl) == MEM
        !          2828:           && GET_CODE (XEXP (rtl, 0)) == REG
        !          2829:           && (REGNO (XEXP (rtl, 0)) < FIRST_VIRTUAL_REGISTER
        !          2830:               || REGNO (XEXP (rtl, 0)) > LAST_VIRTUAL_REGISTER)
        !          2831:           && XEXP (rtl, 0) != current_function_internal_arg_pointer)
        !          2832:     /* This is a variable-sized structure.  */
        !          2833:     emit_insn_after (gen_rtx (USE, VOIDmode, XEXP (rtl, 0)), insn);
        !          2834: }
        !          2835: 
        !          2836: int
        !          2837: max_parm_reg_num ()
        !          2838: {
        !          2839:   return max_parm_reg;
        !          2840: }
        !          2841: 
        !          2842: /* Return the first insn following those generated by `assign_parms'.  */
        !          2843: 
        !          2844: rtx
        !          2845: get_first_nonparm_insn ()
        !          2846: {
        !          2847:   if (last_parm_insn)
        !          2848:     return NEXT_INSN (last_parm_insn);
        !          2849:   return get_insns ();
        !          2850: }
        !          2851: 
        !          2852: /* Return the first NOTE_INSN_BLOCK_BEG note in the function.
        !          2853:    Crash if there is none.  */
        !          2854: 
        !          2855: rtx
        !          2856: get_first_block_beg ()
        !          2857: {
        !          2858:   register rtx searcher;
        !          2859:   register rtx insn = get_first_nonparm_insn ();
        !          2860: 
        !          2861:   for (searcher = insn; searcher; searcher = NEXT_INSN (searcher))
        !          2862:     if (GET_CODE (searcher) == NOTE
        !          2863:        && NOTE_LINE_NUMBER (searcher) == NOTE_INSN_BLOCK_BEG)
        !          2864:       return searcher;
        !          2865: 
        !          2866:   abort ();    /* Invalid call to this function.  (See comments above.)  */
        !          2867:   return NULL_RTX;
        !          2868: }
        !          2869: 
        !          2870: /* Return 1 if EXP is an aggregate type (or a value with aggregate type).
        !          2871:    This means a type for which function calls must pass an address to the
        !          2872:    function or get an address back from the function.
        !          2873:    EXP may be a type node or an expression (whose type is tested).  */
        !          2874: 
        !          2875: int
        !          2876: aggregate_value_p (exp)
        !          2877:      tree exp;
        !          2878: {
        !          2879:   int i, regno, nregs;
        !          2880:   rtx reg;
        !          2881:   tree type;
        !          2882:   if (TREE_CODE_CLASS (TREE_CODE (exp)) == 't')
        !          2883:     type = exp;
        !          2884:   else
        !          2885:     type = TREE_TYPE (exp);
        !          2886: 
        !          2887:   if (RETURN_IN_MEMORY (type))
        !          2888:     return 1;
        !          2889:   if (flag_pcc_struct_return
        !          2890:       && (TREE_CODE (type) == RECORD_TYPE
        !          2891:          || TREE_CODE (type) == UNION_TYPE
        !          2892:          || TREE_CODE (type) == QUAL_UNION_TYPE
        !          2893:          || TREE_CODE (type) == ARRAY_TYPE))
        !          2894:     return 1;
        !          2895:   /* Make sure we have suitable call-clobbered regs to return
        !          2896:      the value in; if not, we must return it in memory.  */
        !          2897:   reg = hard_function_value (type, 0);
        !          2898:   regno = REGNO (reg);
        !          2899:   nregs = HARD_REGNO_NREGS (regno, TYPE_MODE (type));
        !          2900:   for (i = 0; i < nregs; i++)
        !          2901:     if (! call_used_regs[regno + i])
        !          2902:       return 1;
        !          2903:   return 0;
        !          2904: }
        !          2905: 
        !          2906: /* Assign RTL expressions to the function's parameters.
        !          2907:    This may involve copying them into registers and using
        !          2908:    those registers as the RTL for them.
        !          2909: 
        !          2910:    If SECOND_TIME is non-zero it means that this function is being
        !          2911:    called a second time.  This is done by integrate.c when a function's
        !          2912:    compilation is deferred.  We need to come back here in case the
        !          2913:    FUNCTION_ARG macro computes items needed for the rest of the compilation
        !          2914:    (such as changing which registers are fixed or caller-saved).  But suppress
        !          2915:    writing any insns or setting DECL_RTL of anything in this case.  */
        !          2916: 
        !          2917: void
        !          2918: assign_parms (fndecl, second_time)
        !          2919:      tree fndecl;
        !          2920:      int second_time;
        !          2921: {
        !          2922:   register tree parm;
        !          2923:   register rtx entry_parm = 0;
        !          2924:   register rtx stack_parm = 0;
        !          2925:   CUMULATIVE_ARGS args_so_far;
        !          2926:   enum machine_mode promoted_mode, passed_mode, nominal_mode;
        !          2927:   int unsignedp;
        !          2928:   /* Total space needed so far for args on the stack,
        !          2929:      given as a constant and a tree-expression.  */
        !          2930:   struct args_size stack_args_size;
        !          2931:   tree fntype = TREE_TYPE (fndecl);
        !          2932:   tree fnargs = DECL_ARGUMENTS (fndecl);
        !          2933:   /* This is used for the arg pointer when referring to stack args.  */
        !          2934:   rtx internal_arg_pointer;
        !          2935:   /* This is a dummy PARM_DECL that we used for the function result if 
        !          2936:      the function returns a structure.  */
        !          2937:   tree function_result_decl = 0;
        !          2938:   int nparmregs = list_length (fnargs) + LAST_VIRTUAL_REGISTER + 1;
        !          2939:   int varargs_setup = 0;
        !          2940:   rtx conversion_insns = 0;
        !          2941:   /* FUNCTION_ARG may look at this variable.  Since this is not
        !          2942:      expanding a call it will always be zero in this function.  */
        !          2943:   int current_call_is_indirect = 0;
        !          2944: 
        !          2945:   /* Nonzero if the last arg is named `__builtin_va_alist',
        !          2946:      which is used on some machines for old-fashioned non-ANSI varargs.h;
        !          2947:      this should be stuck onto the stack as if it had arrived there.  */
        !          2948:   int vararg
        !          2949:     = (fnargs
        !          2950:        && (parm = tree_last (fnargs)) != 0
        !          2951:        && DECL_NAME (parm)
        !          2952:        && (! strcmp (IDENTIFIER_POINTER (DECL_NAME (parm)),
        !          2953:                     "__builtin_va_alist")));
        !          2954: 
        !          2955:   /* Nonzero if function takes extra anonymous args.
        !          2956:      This means the last named arg must be on the stack
        !          2957:      right before the anonymous ones. */
        !          2958:   int stdarg
        !          2959:     = (TYPE_ARG_TYPES (fntype) != 0
        !          2960:        && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
        !          2961:           != void_type_node));
        !          2962: 
        !          2963:   /* If the reg that the virtual arg pointer will be translated into is
        !          2964:      not a fixed reg or is the stack pointer, make a copy of the virtual
        !          2965:      arg pointer, and address parms via the copy.  The frame pointer is
        !          2966:      considered fixed even though it is not marked as such.
        !          2967: 
        !          2968:      The second time through, simply use ap to avoid generating rtx.  */
        !          2969: 
        !          2970:   if ((ARG_POINTER_REGNUM == STACK_POINTER_REGNUM
        !          2971:        || ! (fixed_regs[ARG_POINTER_REGNUM]
        !          2972:             || ARG_POINTER_REGNUM == FRAME_POINTER_REGNUM))
        !          2973:       && ! second_time)
        !          2974:     internal_arg_pointer = copy_to_reg (virtual_incoming_args_rtx);
        !          2975:   else
        !          2976:     internal_arg_pointer = virtual_incoming_args_rtx;
        !          2977:   current_function_internal_arg_pointer = internal_arg_pointer;
        !          2978: 
        !          2979:   stack_args_size.constant = 0;
        !          2980:   stack_args_size.var = 0;
        !          2981: 
        !          2982:   /* If struct value address is treated as the first argument, make it so.  */
        !          2983:   if (aggregate_value_p (DECL_RESULT (fndecl))
        !          2984:       && ! current_function_returns_pcc_struct
        !          2985:       && struct_value_incoming_rtx == 0)
        !          2986:     {
        !          2987:       tree type = build_pointer_type (fntype);
        !          2988: 
        !          2989:       function_result_decl = build_decl (PARM_DECL, NULL_TREE, type);
        !          2990: 
        !          2991:       DECL_ARG_TYPE (function_result_decl) = type;
        !          2992:       TREE_CHAIN (function_result_decl) = fnargs;
        !          2993:       fnargs = function_result_decl;
        !          2994:     }
        !          2995:                               
        !          2996:   parm_reg_stack_loc = (rtx *) oballoc (nparmregs * sizeof (rtx));
        !          2997:   bzero (parm_reg_stack_loc, nparmregs * sizeof (rtx));
        !          2998: 
        !          2999: #ifdef INIT_CUMULATIVE_INCOMING_ARGS
        !          3000:   INIT_CUMULATIVE_INCOMING_ARGS (args_so_far, fntype, NULL_RTX);
        !          3001: #else
        !          3002:   INIT_CUMULATIVE_ARGS (args_so_far, fntype, NULL_RTX);
        !          3003: #endif
        !          3004: 
        !          3005:   /* We haven't yet found an argument that we must push and pretend the
        !          3006:      caller did.  */
        !          3007:   current_function_pretend_args_size = 0;
        !          3008: 
        !          3009:   for (parm = fnargs; parm; parm = TREE_CHAIN (parm))
        !          3010:     {
        !          3011:       int aggregate
        !          3012:        = (TREE_CODE (TREE_TYPE (parm)) == ARRAY_TYPE
        !          3013:           || TREE_CODE (TREE_TYPE (parm)) == RECORD_TYPE
        !          3014:           || TREE_CODE (TREE_TYPE (parm)) == UNION_TYPE
        !          3015:           || TREE_CODE (TREE_TYPE (parm)) == QUAL_UNION_TYPE);
        !          3016:       struct args_size stack_offset;
        !          3017:       struct args_size arg_size;
        !          3018:       int passed_pointer = 0;
        !          3019:       tree passed_type = DECL_ARG_TYPE (parm);
        !          3020: 
        !          3021:       /* Set LAST_NAMED if this is last named arg before some
        !          3022:         anonymous args.  We treat it as if it were anonymous too.  */
        !          3023:       int last_named = ((TREE_CHAIN (parm) == 0
        !          3024:                         || DECL_NAME (TREE_CHAIN (parm)) == 0)
        !          3025:                        && (vararg || stdarg));
        !          3026: 
        !          3027:       if (TREE_TYPE (parm) == error_mark_node
        !          3028:          /* This can happen after weird syntax errors
        !          3029:             or if an enum type is defined among the parms.  */
        !          3030:          || TREE_CODE (parm) != PARM_DECL
        !          3031:          || passed_type == NULL)
        !          3032:        {
        !          3033:          DECL_INCOMING_RTL (parm) = DECL_RTL (parm) = gen_rtx (MEM, BLKmode,
        !          3034:                                                                const0_rtx);
        !          3035:          TREE_USED (parm) = 1;
        !          3036:          continue;
        !          3037:        }
        !          3038: 
        !          3039:       /* For varargs.h function, save info about regs and stack space
        !          3040:         used by the individual args, not including the va_alist arg.  */
        !          3041:       if (vararg && last_named)
        !          3042:        current_function_args_info = args_so_far;
        !          3043: 
        !          3044:       /* Find mode of arg as it is passed, and mode of arg
        !          3045:         as it should be during execution of this function.  */
        !          3046:       passed_mode = TYPE_MODE (passed_type);
        !          3047:       nominal_mode = TYPE_MODE (TREE_TYPE (parm));
        !          3048: 
        !          3049:       /* If the parm's mode is VOID, its value doesn't matter,
        !          3050:         and avoid the usual things like emit_move_insn that could crash.  */
        !          3051:       if (nominal_mode == VOIDmode)
        !          3052:        {
        !          3053:          DECL_INCOMING_RTL (parm) = DECL_RTL (parm) = const0_rtx;
        !          3054:          continue;
        !          3055:        }
        !          3056: 
        !          3057:       /* See if this arg was passed by invisible reference.  It is if
        !          3058:         it is an object whose size depends on the contents of the
        !          3059:         object itself or if the machine requires these objects be passed
        !          3060:         that way.  */
        !          3061: 
        !          3062:       if ((TREE_CODE (TYPE_SIZE (passed_type)) != INTEGER_CST
        !          3063:           && contains_placeholder_p (TYPE_SIZE (passed_type)))
        !          3064: #ifdef FUNCTION_ARG_PASS_BY_REFERENCE
        !          3065:          || FUNCTION_ARG_PASS_BY_REFERENCE (args_so_far, passed_mode,
        !          3066:                                              passed_type, ! last_named)
        !          3067: #endif
        !          3068:          )
        !          3069:        {
        !          3070:          passed_type = build_pointer_type (passed_type);
        !          3071:          passed_pointer = 1;
        !          3072:          passed_mode = nominal_mode = Pmode;
        !          3073:        }
        !          3074: 
        !          3075:       promoted_mode = passed_mode;
        !          3076: 
        !          3077: #ifdef PROMOTE_FUNCTION_ARGS
        !          3078:       /* Compute the mode in which the arg is actually extended to.  */
        !          3079:       if (TREE_CODE (passed_type) == INTEGER_TYPE
        !          3080:          || TREE_CODE (passed_type) == ENUMERAL_TYPE
        !          3081:          || TREE_CODE (passed_type) == BOOLEAN_TYPE
        !          3082:          || TREE_CODE (passed_type) == CHAR_TYPE
        !          3083:          || TREE_CODE (passed_type) == REAL_TYPE
        !          3084:          || TREE_CODE (passed_type) == POINTER_TYPE
        !          3085:          || TREE_CODE (passed_type) == OFFSET_TYPE)
        !          3086:        {
        !          3087:          unsignedp = TREE_UNSIGNED (passed_type);
        !          3088:          PROMOTE_MODE (promoted_mode, unsignedp, passed_type);
        !          3089:        }
        !          3090: #endif
        !          3091: 
        !          3092:       /* Let machine desc say which reg (if any) the parm arrives in.
        !          3093:         0 means it arrives on the stack.  */
        !          3094: #ifdef FUNCTION_INCOMING_ARG
        !          3095:       entry_parm = FUNCTION_INCOMING_ARG (args_so_far, promoted_mode,
        !          3096:                                          passed_type, ! last_named);
        !          3097: #else
        !          3098:       entry_parm = FUNCTION_ARG (args_so_far, promoted_mode,
        !          3099:                                 passed_type, ! last_named);
        !          3100: #endif
        !          3101: 
        !          3102:       if (entry_parm)
        !          3103:        passed_mode = promoted_mode;
        !          3104: 
        !          3105: #ifdef SETUP_INCOMING_VARARGS
        !          3106:       /* If this is the last named parameter, do any required setup for
        !          3107:         varargs or stdargs.  We need to know about the case of this being an
        !          3108:         addressable type, in which case we skip the registers it
        !          3109:         would have arrived in.
        !          3110: 
        !          3111:         For stdargs, LAST_NAMED will be set for two parameters, the one that
        !          3112:         is actually the last named, and the dummy parameter.  We only
        !          3113:         want to do this action once.
        !          3114: 
        !          3115:         Also, indicate when RTL generation is to be suppressed.  */
        !          3116:       if (last_named && !varargs_setup)
        !          3117:        {
        !          3118:          SETUP_INCOMING_VARARGS (args_so_far, passed_mode, passed_type,
        !          3119:                                  current_function_pretend_args_size,
        !          3120:                                  second_time);
        !          3121:          varargs_setup = 1;
        !          3122:        }
        !          3123: #endif
        !          3124: 
        !          3125:       /* Determine parm's home in the stack,
        !          3126:         in case it arrives in the stack or we should pretend it did.
        !          3127: 
        !          3128:         Compute the stack position and rtx where the argument arrives
        !          3129:         and its size.
        !          3130: 
        !          3131:         There is one complexity here:  If this was a parameter that would
        !          3132:         have been passed in registers, but wasn't only because it is
        !          3133:         __builtin_va_alist, we want locate_and_pad_parm to treat it as if
        !          3134:         it came in a register so that REG_PARM_STACK_SPACE isn't skipped.
        !          3135:         In this case, we call FUNCTION_ARG with NAMED set to 1 instead of
        !          3136:         0 as it was the previous time.  */
        !          3137: 
        !          3138:       locate_and_pad_parm (passed_mode, passed_type,
        !          3139: #ifdef STACK_PARMS_IN_REG_PARM_AREA
        !          3140:                           1,
        !          3141: #else
        !          3142: #ifdef FUNCTION_INCOMING_ARG
        !          3143:                           FUNCTION_INCOMING_ARG (args_so_far, passed_mode,
        !          3144:                                                  passed_type,
        !          3145:                                                  (! last_named
        !          3146:                                                   || varargs_setup)) != 0,
        !          3147: #else
        !          3148:                           FUNCTION_ARG (args_so_far, passed_mode,
        !          3149:                                         passed_type,
        !          3150:                                         ! last_named || varargs_setup) != 0,
        !          3151: #endif
        !          3152: #endif
        !          3153:                           fndecl, &stack_args_size, &stack_offset, &arg_size);
        !          3154: 
        !          3155:       if (! second_time)
        !          3156:        {
        !          3157:          rtx offset_rtx = ARGS_SIZE_RTX (stack_offset);
        !          3158: 
        !          3159:          if (offset_rtx == const0_rtx)
        !          3160:            stack_parm = gen_rtx (MEM, passed_mode, internal_arg_pointer);
        !          3161:          else
        !          3162:            stack_parm = gen_rtx (MEM, passed_mode,
        !          3163:                                  gen_rtx (PLUS, Pmode,
        !          3164:                                           internal_arg_pointer, offset_rtx));
        !          3165: 
        !          3166:          /* If this is a memory ref that contains aggregate components,
        !          3167:             mark it as such for cse and loop optimize.  */
        !          3168:          MEM_IN_STRUCT_P (stack_parm) = aggregate;
        !          3169:        }
        !          3170: 
        !          3171:       /* If this parameter was passed both in registers and in the stack,
        !          3172:         use the copy on the stack.  */
        !          3173:       if (MUST_PASS_IN_STACK (passed_mode, passed_type))
        !          3174:        entry_parm = 0;
        !          3175: 
        !          3176: #ifdef FUNCTION_ARG_PARTIAL_NREGS
        !          3177:       /* If this parm was passed part in regs and part in memory,
        !          3178:         pretend it arrived entirely in memory
        !          3179:         by pushing the register-part onto the stack.
        !          3180: 
        !          3181:         In the special case of a DImode or DFmode that is split,
        !          3182:         we could put it together in a pseudoreg directly,
        !          3183:         but for now that's not worth bothering with.  */
        !          3184: 
        !          3185:       if (entry_parm)
        !          3186:        {
        !          3187:          int nregs = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, passed_mode,
        !          3188:                                                  passed_type, ! last_named);
        !          3189: 
        !          3190:          if (nregs > 0)
        !          3191:            {
        !          3192:              current_function_pretend_args_size
        !          3193:                = (((nregs * UNITS_PER_WORD) + (PARM_BOUNDARY / BITS_PER_UNIT) - 1)
        !          3194:                   / (PARM_BOUNDARY / BITS_PER_UNIT)
        !          3195:                   * (PARM_BOUNDARY / BITS_PER_UNIT));
        !          3196: 
        !          3197:              if (! second_time)
        !          3198:                move_block_from_reg (REGNO (entry_parm),
        !          3199:                                     validize_mem (stack_parm), nregs,
        !          3200:                                     int_size_in_bytes (TREE_TYPE (parm)));
        !          3201:              entry_parm = stack_parm;
        !          3202:            }
        !          3203:        }
        !          3204: #endif
        !          3205: 
        !          3206:       /* If we didn't decide this parm came in a register,
        !          3207:         by default it came on the stack.  */
        !          3208:       if (entry_parm == 0)
        !          3209:        entry_parm = stack_parm;
        !          3210: 
        !          3211:       /* Record permanently how this parm was passed.  */
        !          3212:       if (! second_time)
        !          3213:        DECL_INCOMING_RTL (parm) = entry_parm;
        !          3214: 
        !          3215:       /* If there is actually space on the stack for this parm,
        !          3216:         count it in stack_args_size; otherwise set stack_parm to 0
        !          3217:         to indicate there is no preallocated stack slot for the parm.  */
        !          3218: 
        !          3219:       if (entry_parm == stack_parm
        !          3220: #if defined (REG_PARM_STACK_SPACE) && ! defined (MAYBE_REG_PARM_STACK_SPACE)
        !          3221:          /* On some machines, even if a parm value arrives in a register
        !          3222:             there is still an (uninitialized) stack slot allocated for it.
        !          3223: 
        !          3224:             ??? When MAYBE_REG_PARM_STACK_SPACE is defined, we can't tell
        !          3225:             whether this parameter already has a stack slot allocated,
        !          3226:             because an arg block exists only if current_function_args_size
        !          3227:             is larger than some threshhold, and we haven't calculated that
        !          3228:             yet.  So, for now, we just assume that stack slots never exist
        !          3229:             in this case.  */
        !          3230:          || REG_PARM_STACK_SPACE (fndecl) > 0
        !          3231: #endif
        !          3232:          )
        !          3233:        {
        !          3234:          stack_args_size.constant += arg_size.constant;
        !          3235:          if (arg_size.var)
        !          3236:            ADD_PARM_SIZE (stack_args_size, arg_size.var);
        !          3237:        }
        !          3238:       else
        !          3239:        /* No stack slot was pushed for this parm.  */
        !          3240:        stack_parm = 0;
        !          3241: 
        !          3242:       /* Update info on where next arg arrives in registers.  */
        !          3243: 
        !          3244:       FUNCTION_ARG_ADVANCE (args_so_far, passed_mode,
        !          3245:                            passed_type, ! last_named);
        !          3246: 
        !          3247:       /* If this is our second time through, we are done with this parm. */
        !          3248:       if (second_time)
        !          3249:        continue;
        !          3250: 
        !          3251:       /* If we can't trust the parm stack slot to be aligned enough
        !          3252:         for its ultimate type, don't use that slot after entry.
        !          3253:         We'll make another stack slot, if we need one.  */
        !          3254:       {
        !          3255:        int thisparm_boundary
        !          3256:          = FUNCTION_ARG_BOUNDARY (passed_mode, passed_type);
        !          3257: 
        !          3258:        if (GET_MODE_ALIGNMENT (nominal_mode) > thisparm_boundary)
        !          3259:          stack_parm = 0;
        !          3260:       }
        !          3261: 
        !          3262:       /* If parm was passed in memory, and we need to convert it on entry,
        !          3263:         don't store it back in that same slot.  */
        !          3264:       if (entry_parm != 0
        !          3265:          && nominal_mode != BLKmode && nominal_mode != passed_mode)
        !          3266:        stack_parm = 0;
        !          3267: 
        !          3268: #if 0
        !          3269:       /* Now adjust STACK_PARM to the mode and precise location
        !          3270:         where this parameter should live during execution,
        !          3271:         if we discover that it must live in the stack during execution.
        !          3272:         To make debuggers happier on big-endian machines, we store
        !          3273:         the value in the last bytes of the space available.  */
        !          3274: 
        !          3275:       if (nominal_mode != BLKmode && nominal_mode != passed_mode
        !          3276:          && stack_parm != 0)
        !          3277:        {
        !          3278:          rtx offset_rtx;
        !          3279: 
        !          3280: #if BYTES_BIG_ENDIAN
        !          3281:          if (GET_MODE_SIZE (nominal_mode) < UNITS_PER_WORD)
        !          3282:            stack_offset.constant += (GET_MODE_SIZE (passed_mode)
        !          3283:                                      - GET_MODE_SIZE (nominal_mode));
        !          3284: #endif
        !          3285: 
        !          3286:          offset_rtx = ARGS_SIZE_RTX (stack_offset);
        !          3287:          if (offset_rtx == const0_rtx)
        !          3288:            stack_parm = gen_rtx (MEM, nominal_mode, internal_arg_pointer);
        !          3289:          else
        !          3290:            stack_parm = gen_rtx (MEM, nominal_mode,
        !          3291:                                  gen_rtx (PLUS, Pmode,
        !          3292:                                           internal_arg_pointer, offset_rtx));
        !          3293: 
        !          3294:          /* If this is a memory ref that contains aggregate components,
        !          3295:             mark it as such for cse and loop optimize.  */
        !          3296:          MEM_IN_STRUCT_P (stack_parm) = aggregate;
        !          3297:        }
        !          3298: #endif /* 0 */
        !          3299: 
        !          3300:       /* ENTRY_PARM is an RTX for the parameter as it arrives,
        !          3301:         in the mode in which it arrives.
        !          3302:         STACK_PARM is an RTX for a stack slot where the parameter can live
        !          3303:         during the function (in case we want to put it there).
        !          3304:         STACK_PARM is 0 if no stack slot was pushed for it.
        !          3305: 
        !          3306:         Now output code if necessary to convert ENTRY_PARM to
        !          3307:         the type in which this function declares it,
        !          3308:         and store that result in an appropriate place,
        !          3309:         which may be a pseudo reg, may be STACK_PARM,
        !          3310:         or may be a local stack slot if STACK_PARM is 0.
        !          3311: 
        !          3312:         Set DECL_RTL to that place.  */
        !          3313: 
        !          3314:       if (nominal_mode == BLKmode)
        !          3315:        {
        !          3316:          /* If a BLKmode arrives in registers, copy it to a stack slot.  */
        !          3317:          if (GET_CODE (entry_parm) == REG)
        !          3318:            {
        !          3319:              int size_stored = CEIL_ROUND (int_size_in_bytes (TREE_TYPE (parm)),
        !          3320:                                            UNITS_PER_WORD);
        !          3321: 
        !          3322:              /* Note that we will be storing an integral number of words.
        !          3323:                 So we have to be careful to ensure that we allocate an
        !          3324:                 integral number of words.  We do this below in the
        !          3325:                 assign_stack_local if space was not allocated in the argument
        !          3326:                 list.  If it was, this will not work if PARM_BOUNDARY is not
        !          3327:                 a multiple of BITS_PER_WORD.  It isn't clear how to fix this
        !          3328:                 if it becomes a problem.  */
        !          3329: 
        !          3330:              if (stack_parm == 0)
        !          3331:                {
        !          3332:                  stack_parm
        !          3333:                    = assign_stack_local (GET_MODE (entry_parm), size_stored, 0);
        !          3334:                  /* If this is a memory ref that contains aggregate components,
        !          3335:                     mark it as such for cse and loop optimize.  */
        !          3336:                  MEM_IN_STRUCT_P (stack_parm) = aggregate;
        !          3337:                }
        !          3338: 
        !          3339:              else if (PARM_BOUNDARY % BITS_PER_WORD != 0)
        !          3340:                abort ();
        !          3341: 
        !          3342:              move_block_from_reg (REGNO (entry_parm),
        !          3343:                                   validize_mem (stack_parm),
        !          3344:                                   size_stored / UNITS_PER_WORD,
        !          3345:                                   int_size_in_bytes (TREE_TYPE (parm)));
        !          3346:            }
        !          3347:          DECL_RTL (parm) = stack_parm;
        !          3348:        }
        !          3349:       else if (! ((obey_regdecls && ! DECL_REGISTER (parm)
        !          3350:                   && ! DECL_INLINE (fndecl))
        !          3351:                  /* layout_decl may set this.  */
        !          3352:                  || TREE_ADDRESSABLE (parm)
        !          3353:                  || TREE_SIDE_EFFECTS (parm)
        !          3354:                  /* If -ffloat-store specified, don't put explicit
        !          3355:                     float variables into registers.  */
        !          3356:                  || (flag_float_store
        !          3357:                      && TREE_CODE (TREE_TYPE (parm)) == REAL_TYPE))
        !          3358:               /* Always assign pseudo to structure return or item passed
        !          3359:                  by invisible reference.  */
        !          3360:               || passed_pointer || parm == function_result_decl)
        !          3361:        {
        !          3362:          /* Store the parm in a pseudoregister during the function, but we
        !          3363:             may need to do it in a wider mode.  */
        !          3364: 
        !          3365:          register rtx parmreg;
        !          3366:          int regno;
        !          3367: 
        !          3368:          unsignedp = TREE_UNSIGNED (TREE_TYPE (parm));
        !          3369:          if (TREE_CODE (TREE_TYPE (parm)) == INTEGER_TYPE
        !          3370:              || TREE_CODE (TREE_TYPE (parm)) == ENUMERAL_TYPE
        !          3371:              || TREE_CODE (TREE_TYPE (parm)) == BOOLEAN_TYPE
        !          3372:              || TREE_CODE (TREE_TYPE (parm)) == CHAR_TYPE
        !          3373:              || TREE_CODE (TREE_TYPE (parm)) == REAL_TYPE
        !          3374:              || TREE_CODE (TREE_TYPE (parm)) == POINTER_TYPE
        !          3375:              || TREE_CODE (TREE_TYPE (parm)) == OFFSET_TYPE)
        !          3376:            {
        !          3377:              PROMOTE_MODE (nominal_mode, unsignedp, TREE_TYPE (parm));
        !          3378:            }
        !          3379: 
        !          3380:          parmreg = gen_reg_rtx (nominal_mode);
        !          3381:          REG_USERVAR_P (parmreg) = 1;
        !          3382: 
        !          3383:          /* If this was an item that we received a pointer to, set DECL_RTL
        !          3384:             appropriately.  */
        !          3385:          if (passed_pointer)
        !          3386:            {
        !          3387:              DECL_RTL (parm) = gen_rtx (MEM, TYPE_MODE (TREE_TYPE (passed_type)), parmreg);
        !          3388:              MEM_IN_STRUCT_P (DECL_RTL (parm)) = aggregate;
        !          3389:            }
        !          3390:          else
        !          3391:            DECL_RTL (parm) = parmreg;
        !          3392: 
        !          3393:          /* Copy the value into the register.  */
        !          3394:          if (GET_MODE (parmreg) != GET_MODE (entry_parm))
        !          3395:            {
        !          3396:              /* If ENTRY_PARM is a hard register, it might be in a register
        !          3397:                 not valid for operating in its mode (e.g., an odd-numbered
        !          3398:                 register for a DFmode).  In that case, moves are the only
        !          3399:                 thing valid, so we can't do a convert from there.  This
        !          3400:                 occurs when the calling sequence allow such misaligned
        !          3401:                 usages.
        !          3402: 
        !          3403:                 In addition, the conversion may involve a call, which could
        !          3404:                 clobber parameters which haven't been copied to pseudo
        !          3405:                 registers yet.  Therefore, we must first copy the parm to
        !          3406:                 a pseudo reg here, and save the conversion until after all
        !          3407:                 parameters have been moved.  */
        !          3408: 
        !          3409:              rtx tempreg = gen_reg_rtx (GET_MODE (entry_parm));
        !          3410: 
        !          3411:              emit_move_insn (tempreg, validize_mem (entry_parm));
        !          3412: 
        !          3413:              push_to_sequence (conversion_insns);
        !          3414:              convert_move (parmreg, tempreg, unsignedp);
        !          3415:              conversion_insns = get_insns ();
        !          3416:              end_sequence ();
        !          3417:            }
        !          3418:          else
        !          3419:            emit_move_insn (parmreg, validize_mem (entry_parm));
        !          3420: 
        !          3421:          /* If we were passed a pointer but the actual value
        !          3422:             can safely live in a register, put it in one.  */
        !          3423:          if (passed_pointer && TYPE_MODE (TREE_TYPE (parm)) != BLKmode
        !          3424:              && ! ((obey_regdecls && ! DECL_REGISTER (parm)
        !          3425:                     && ! DECL_INLINE (fndecl))
        !          3426:                    /* layout_decl may set this.  */
        !          3427:                    || TREE_ADDRESSABLE (parm)
        !          3428:                    || TREE_SIDE_EFFECTS (parm)
        !          3429:                    /* If -ffloat-store specified, don't put explicit
        !          3430:                       float variables into registers.  */
        !          3431:                    || (flag_float_store
        !          3432:                        && TREE_CODE (TREE_TYPE (parm)) == REAL_TYPE)))
        !          3433:            {
        !          3434:              /* We can't use nominal_mode, because it will have been set to
        !          3435:                 Pmode above.  We must use the actual mode of the parm.  */
        !          3436:              parmreg = gen_reg_rtx (TYPE_MODE (TREE_TYPE (parm)));
        !          3437:              emit_move_insn (parmreg, DECL_RTL (parm));
        !          3438:              DECL_RTL (parm) = parmreg;
        !          3439:              /* STACK_PARM is the pointer, not the parm, and PARMREG is
        !          3440:                 now the parm.  */
        !          3441:              stack_parm = 0;
        !          3442:            }
        !          3443: #ifdef FUNCTION_ARG_CALLEE_COPIES
        !          3444:          /* If we are passed an arg by reference and it is our responsibility
        !          3445:             to make a copy, do it now.
        !          3446:             PASSED_TYPE and PASSED mode now refer to the pointer, not the
        !          3447:             original argument, so we must recreate them in the call to
        !          3448:             FUNCTION_ARG_CALLEE_COPIES.  */
        !          3449:          /* ??? Later add code to handle the case that if the argument isn't
        !          3450:             modified, don't do the copy.  */
        !          3451: 
        !          3452:          else if (passed_pointer
        !          3453:                   && FUNCTION_ARG_CALLEE_COPIES (args_so_far,
        !          3454:                                                  TYPE_MODE (DECL_ARG_TYPE (parm)),
        !          3455:                                                  DECL_ARG_TYPE (parm),
        !          3456:                                                  ! last_named))
        !          3457:            {
        !          3458:              rtx copy;
        !          3459:              tree type = DECL_ARG_TYPE (parm);
        !          3460: 
        !          3461:              /* This sequence may involve a library call perhaps clobbering
        !          3462:                 registers that haven't been copied to pseudos yet.  */
        !          3463: 
        !          3464:              push_to_sequence (conversion_insns);
        !          3465: 
        !          3466:              if (TYPE_SIZE (type) == 0
        !          3467:                  || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
        !          3468:                {
        !          3469:                  /* This is a variable sized object.  */
        !          3470:                  /* ??? Can we use expr_size here?  */
        !          3471:                  rtx size_rtx = expand_expr (size_in_bytes (type), NULL_RTX,
        !          3472:                                              TYPE_MODE (sizetype), 0);
        !          3473: 
        !          3474:                  copy = gen_rtx (MEM, BLKmode,
        !          3475:                                  allocate_dynamic_stack_space (size_rtx, NULL_RTX,
        !          3476:                                                                TYPE_ALIGN (type)));
        !          3477:                }
        !          3478:              else
        !          3479:                {
        !          3480:                  int size = int_size_in_bytes (type);
        !          3481:                  copy = assign_stack_temp (TYPE_MODE (type), size, 1);
        !          3482:                }
        !          3483: 
        !          3484:              store_expr (parm, copy, 0);
        !          3485:              emit_move_insn (parmreg, XEXP (copy, 0));
        !          3486:              conversion_insns = get_insns ();
        !          3487:              end_sequence ();
        !          3488:            }
        !          3489: #endif /* FUNCTION_ARG_CALLEE_COPIES */
        !          3490: 
        !          3491:          /* In any case, record the parm's desired stack location
        !          3492:             in case we later discover it must live in the stack. 
        !          3493: 
        !          3494:             If it is a COMPLEX value, store the stack location for both
        !          3495:             halves.  */
        !          3496: 
        !          3497:          if (GET_CODE (parmreg) == CONCAT)
        !          3498:            regno = MAX (REGNO (XEXP (parmreg, 0)), REGNO (XEXP (parmreg, 1)));
        !          3499:          else
        !          3500:            regno = REGNO (parmreg);
        !          3501: 
        !          3502:          if (regno >= nparmregs)
        !          3503:            {
        !          3504:              rtx *new;
        !          3505:              int old_nparmregs = nparmregs;
        !          3506: 
        !          3507:              nparmregs = regno + 5;
        !          3508:              new = (rtx *) oballoc (nparmregs * sizeof (rtx));
        !          3509:              bcopy (parm_reg_stack_loc, new, old_nparmregs * sizeof (rtx));
        !          3510:              bzero (new + old_nparmregs,
        !          3511:                     (nparmregs - old_nparmregs) * sizeof (rtx));
        !          3512:              parm_reg_stack_loc = new;
        !          3513:            }
        !          3514: 
        !          3515:          if (GET_CODE (parmreg) == CONCAT)
        !          3516:            {
        !          3517:              enum machine_mode submode = GET_MODE (XEXP (parmreg, 0));
        !          3518: 
        !          3519:              if (stack_parm != 0)
        !          3520:                {
        !          3521:                  parm_reg_stack_loc[REGNO (gen_lowpart (submode, parmreg))]
        !          3522:                    = gen_lowpart (submode, stack_parm);
        !          3523:                  parm_reg_stack_loc[REGNO (gen_highpart (submode, parmreg))]
        !          3524:                    = gen_highpart (submode, stack_parm);
        !          3525:                }
        !          3526:              else
        !          3527:                {
        !          3528:                  parm_reg_stack_loc[REGNO (gen_lowpart (submode, parmreg))]
        !          3529:                    = 0;
        !          3530:                  parm_reg_stack_loc[REGNO (gen_highpart (submode, parmreg))]
        !          3531:                    = 0;
        !          3532:                }
        !          3533:            }
        !          3534:          else
        !          3535:            parm_reg_stack_loc[REGNO (parmreg)] = stack_parm;
        !          3536: 
        !          3537:          /* Mark the register as eliminable if we did no conversion
        !          3538:             and it was copied from memory at a fixed offset,
        !          3539:             and the arg pointer was not copied to a pseudo-reg.
        !          3540:             If the arg pointer is a pseudo reg or the offset formed
        !          3541:             an invalid address, such memory-equivalences
        !          3542:             as we make here would screw up life analysis for it.  */
        !          3543:          if (nominal_mode == passed_mode
        !          3544:              && GET_CODE (entry_parm) == MEM
        !          3545:              && entry_parm == stack_parm
        !          3546:              && stack_offset.var == 0
        !          3547:              && reg_mentioned_p (virtual_incoming_args_rtx,
        !          3548:                                  XEXP (entry_parm, 0)))
        !          3549:            REG_NOTES (get_last_insn ())
        !          3550:              = gen_rtx (EXPR_LIST, REG_EQUIV,
        !          3551:                         entry_parm, REG_NOTES (get_last_insn ()));
        !          3552: 
        !          3553:          /* For pointer data type, suggest pointer register.  */
        !          3554:          if (TREE_CODE (TREE_TYPE (parm)) == POINTER_TYPE)
        !          3555:            mark_reg_pointer (parmreg);
        !          3556:        }
        !          3557:       else
        !          3558:        {
        !          3559:          /* Value must be stored in the stack slot STACK_PARM
        !          3560:             during function execution.  */
        !          3561: 
        !          3562:          if (passed_mode != nominal_mode)
        !          3563:            {
        !          3564:              /* Conversion is required.   */
        !          3565:              rtx tempreg = gen_reg_rtx (GET_MODE (entry_parm));
        !          3566: 
        !          3567:              emit_move_insn (tempreg, validize_mem (entry_parm));
        !          3568: 
        !          3569:              push_to_sequence (conversion_insns);
        !          3570:              entry_parm = convert_to_mode (nominal_mode, tempreg,
        !          3571:                                            TREE_UNSIGNED (TREE_TYPE (parm)));
        !          3572:              conversion_insns = get_insns ();
        !          3573:              end_sequence ();
        !          3574:            }
        !          3575: 
        !          3576:          if (entry_parm != stack_parm)
        !          3577:            {
        !          3578:              if (stack_parm == 0)
        !          3579:                {
        !          3580:                  stack_parm
        !          3581:                    = assign_stack_local (GET_MODE (entry_parm),
        !          3582:                                          GET_MODE_SIZE (GET_MODE (entry_parm)), 0);
        !          3583:                  /* If this is a memory ref that contains aggregate components,
        !          3584:                     mark it as such for cse and loop optimize.  */
        !          3585:                  MEM_IN_STRUCT_P (stack_parm) = aggregate;
        !          3586:                }
        !          3587: 
        !          3588:              if (passed_mode != nominal_mode)
        !          3589:                {
        !          3590:                  push_to_sequence (conversion_insns);
        !          3591:                  emit_move_insn (validize_mem (stack_parm),
        !          3592:                                  validize_mem (entry_parm));
        !          3593:                  conversion_insns = get_insns ();
        !          3594:                  end_sequence ();
        !          3595:                }
        !          3596:              else
        !          3597:                emit_move_insn (validize_mem (stack_parm),
        !          3598:                                validize_mem (entry_parm));
        !          3599:            }
        !          3600: 
        !          3601:          DECL_RTL (parm) = stack_parm;
        !          3602:        }
        !          3603:       
        !          3604:       /* If this "parameter" was the place where we are receiving the
        !          3605:         function's incoming structure pointer, set up the result.  */
        !          3606:       if (parm == function_result_decl)
        !          3607:        DECL_RTL (DECL_RESULT (fndecl))
        !          3608:          = gen_rtx (MEM, DECL_MODE (DECL_RESULT (fndecl)), DECL_RTL (parm));
        !          3609: 
        !          3610:       if (TREE_THIS_VOLATILE (parm))
        !          3611:        MEM_VOLATILE_P (DECL_RTL (parm)) = 1;
        !          3612:       if (TREE_READONLY (parm))
        !          3613:        RTX_UNCHANGING_P (DECL_RTL (parm)) = 1;
        !          3614:     }
        !          3615: 
        !          3616:   /* Output all parameter conversion instructions (possibly including calls)
        !          3617:      now that all parameters have been copied out of hard registers.  */
        !          3618:   emit_insns (conversion_insns);
        !          3619: 
        !          3620:   max_parm_reg = max_reg_num ();
        !          3621:   last_parm_insn = get_last_insn ();
        !          3622: 
        !          3623:   current_function_args_size = stack_args_size.constant;
        !          3624: 
        !          3625:   /* Adjust function incoming argument size for alignment and
        !          3626:      minimum length.  */
        !          3627: 
        !          3628: #ifdef REG_PARM_STACK_SPACE
        !          3629: #ifndef MAYBE_REG_PARM_STACK_SPACE
        !          3630:   current_function_args_size = MAX (current_function_args_size,
        !          3631:                                    REG_PARM_STACK_SPACE (fndecl));
        !          3632: #endif
        !          3633: #endif
        !          3634: 
        !          3635: #ifdef STACK_BOUNDARY
        !          3636: #define STACK_BYTES (STACK_BOUNDARY / BITS_PER_UNIT)
        !          3637: 
        !          3638:   current_function_args_size
        !          3639:     = ((current_function_args_size + STACK_BYTES - 1)
        !          3640:        / STACK_BYTES) * STACK_BYTES;
        !          3641: #endif  
        !          3642: 
        !          3643: #ifdef ARGS_GROW_DOWNWARD
        !          3644:   current_function_arg_offset_rtx
        !          3645:     = (stack_args_size.var == 0 ? GEN_INT (-stack_args_size.constant)
        !          3646:        : expand_expr (size_binop (MINUS_EXPR, stack_args_size.var,     
        !          3647:                                  size_int (-stack_args_size.constant)),   
        !          3648:                      NULL_RTX, VOIDmode, 0));
        !          3649: #else
        !          3650:   current_function_arg_offset_rtx = ARGS_SIZE_RTX (stack_args_size);
        !          3651: #endif
        !          3652: 
        !          3653:   /* See how many bytes, if any, of its args a function should try to pop
        !          3654:      on return.  */
        !          3655: 
        !          3656:   current_function_pops_args = RETURN_POPS_ARGS (TREE_TYPE (fndecl),
        !          3657:                                                 current_function_args_size);
        !          3658: 
        !          3659:   /* For stdarg.h function, save info about regs and stack space
        !          3660:      used by the named args.  */
        !          3661: 
        !          3662:   if (stdarg)
        !          3663:     current_function_args_info = args_so_far;
        !          3664: 
        !          3665:   /* Set the rtx used for the function return value.  Put this in its
        !          3666:      own variable so any optimizers that need this information don't have
        !          3667:      to include tree.h.  Do this here so it gets done when an inlined
        !          3668:      function gets output.  */
        !          3669: 
        !          3670:   current_function_return_rtx = DECL_RTL (DECL_RESULT (fndecl));
        !          3671: }
        !          3672: 
        !          3673: /* Indicate whether REGNO is an incoming argument to the current function
        !          3674:    that was promoted to a wider mode.  If so, return the RTX for the
        !          3675:    register (to get its mode).  PMODE and PUNSIGNEDP are set to the mode
        !          3676:    that REGNO is promoted from and whether the promotion was signed or
        !          3677:    unsigned.  */
        !          3678: 
        !          3679: #ifdef PROMOTE_FUNCTION_ARGS
        !          3680: 
        !          3681: rtx
        !          3682: promoted_input_arg (regno, pmode, punsignedp)
        !          3683:      int regno;
        !          3684:      enum machine_mode *pmode;
        !          3685:      int *punsignedp;
        !          3686: {
        !          3687:   tree arg;
        !          3688: 
        !          3689:   for (arg = DECL_ARGUMENTS (current_function_decl); arg;
        !          3690:        arg = TREE_CHAIN (arg))
        !          3691:     if (GET_CODE (DECL_INCOMING_RTL (arg)) == REG
        !          3692:        && REGNO (DECL_INCOMING_RTL (arg)) == regno
        !          3693:        && (TREE_CODE (TREE_TYPE (arg)) == INTEGER_TYPE
        !          3694:            || TREE_CODE (TREE_TYPE (arg)) == ENUMERAL_TYPE
        !          3695:            || TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE
        !          3696:            || TREE_CODE (TREE_TYPE (arg)) == CHAR_TYPE
        !          3697:            || TREE_CODE (TREE_TYPE (arg)) == REAL_TYPE
        !          3698:            || TREE_CODE (TREE_TYPE (arg)) == POINTER_TYPE
        !          3699:            || TREE_CODE (TREE_TYPE (arg)) == OFFSET_TYPE))
        !          3700:       {
        !          3701:        enum machine_mode mode = TYPE_MODE (TREE_TYPE (arg));
        !          3702:        int unsignedp = TREE_UNSIGNED (TREE_TYPE (arg));
        !          3703: 
        !          3704:        PROMOTE_MODE (mode, unsignedp, TREE_TYPE (arg));
        !          3705:        if (mode == GET_MODE (DECL_INCOMING_RTL (arg))
        !          3706:            && mode != DECL_MODE (arg))
        !          3707:          {
        !          3708:            *pmode = DECL_MODE (arg);
        !          3709:            *punsignedp = unsignedp;
        !          3710:            return DECL_INCOMING_RTL (arg);
        !          3711:          }
        !          3712:       }
        !          3713: 
        !          3714:   return 0;
        !          3715: }
        !          3716: 
        !          3717: #endif
        !          3718: 
        !          3719: /* Compute the size and offset from the start of the stacked arguments for a
        !          3720:    parm passed in mode PASSED_MODE and with type TYPE.
        !          3721: 
        !          3722:    INITIAL_OFFSET_PTR points to the current offset into the stacked
        !          3723:    arguments.
        !          3724: 
        !          3725:    The starting offset and size for this parm are returned in *OFFSET_PTR
        !          3726:    and *ARG_SIZE_PTR, respectively.
        !          3727: 
        !          3728:    IN_REGS is non-zero if the argument will be passed in registers.  It will
        !          3729:    never be set if REG_PARM_STACK_SPACE is not defined.
        !          3730: 
        !          3731:    FNDECL is the function in which the argument was defined.
        !          3732: 
        !          3733:    There are two types of rounding that are done.  The first, controlled by
        !          3734:    FUNCTION_ARG_BOUNDARY, forces the offset from the start of the argument
        !          3735:    list to be aligned to the specific boundary (in bits).  This rounding
        !          3736:    affects the initial and starting offsets, but not the argument size.
        !          3737: 
        !          3738:    The second, controlled by FUNCTION_ARG_PADDING and PARM_BOUNDARY,
        !          3739:    optionally rounds the size of the parm to PARM_BOUNDARY.  The
        !          3740:    initial offset is not affected by this rounding, while the size always
        !          3741:    is and the starting offset may be.  */
        !          3742: 
        !          3743: /*  offset_ptr will be negative for ARGS_GROW_DOWNWARD case; 
        !          3744:     initial_offset_ptr is positive because locate_and_pad_parm's
        !          3745:     callers pass in the total size of args so far as
        !          3746:     initial_offset_ptr. arg_size_ptr is always positive.*/
        !          3747: 
        !          3748: static void pad_to_arg_alignment (), pad_below ();
        !          3749: 
        !          3750: void
        !          3751: locate_and_pad_parm (passed_mode, type, in_regs, fndecl,
        !          3752:                     initial_offset_ptr, offset_ptr, arg_size_ptr)
        !          3753:      enum machine_mode passed_mode;
        !          3754:      tree type;
        !          3755:      int in_regs;
        !          3756:      tree fndecl;
        !          3757:      struct args_size *initial_offset_ptr;
        !          3758:      struct args_size *offset_ptr;
        !          3759:      struct args_size *arg_size_ptr;
        !          3760: {
        !          3761:   tree sizetree
        !          3762:     = type ? size_in_bytes (type) : size_int (GET_MODE_SIZE (passed_mode));
        !          3763:   enum direction where_pad = FUNCTION_ARG_PADDING (passed_mode, type);
        !          3764:   int boundary = FUNCTION_ARG_BOUNDARY (passed_mode, type);
        !          3765:   int boundary_in_bytes = boundary / BITS_PER_UNIT;
        !          3766:   int reg_parm_stack_space = 0;
        !          3767: 
        !          3768: #ifdef REG_PARM_STACK_SPACE
        !          3769:   /* If we have found a stack parm before we reach the end of the
        !          3770:      area reserved for registers, skip that area.  */
        !          3771:   if (! in_regs)
        !          3772:     {
        !          3773: #ifdef MAYBE_REG_PARM_STACK_SPACE
        !          3774:       reg_parm_stack_space = MAYBE_REG_PARM_STACK_SPACE;
        !          3775: #else
        !          3776:       reg_parm_stack_space = REG_PARM_STACK_SPACE (fndecl);
        !          3777: #endif
        !          3778:       if (reg_parm_stack_space > 0)
        !          3779:        {
        !          3780:          if (initial_offset_ptr->var)
        !          3781:            {
        !          3782:              initial_offset_ptr->var
        !          3783:                = size_binop (MAX_EXPR, ARGS_SIZE_TREE (*initial_offset_ptr),
        !          3784:                              size_int (reg_parm_stack_space));
        !          3785:              initial_offset_ptr->constant = 0;
        !          3786:            }
        !          3787:          else if (initial_offset_ptr->constant < reg_parm_stack_space)
        !          3788:            initial_offset_ptr->constant = reg_parm_stack_space;
        !          3789:        }
        !          3790:     }
        !          3791: #endif /* REG_PARM_STACK_SPACE */
        !          3792: 
        !          3793:   arg_size_ptr->var = 0;
        !          3794:   arg_size_ptr->constant = 0;
        !          3795: 
        !          3796: #ifdef ARGS_GROW_DOWNWARD
        !          3797:   if (initial_offset_ptr->var)
        !          3798:     {
        !          3799:       offset_ptr->constant = 0;
        !          3800:       offset_ptr->var = size_binop (MINUS_EXPR, integer_zero_node,
        !          3801:                                    initial_offset_ptr->var);
        !          3802:     }
        !          3803:   else
        !          3804:     {
        !          3805:       offset_ptr->constant = - initial_offset_ptr->constant;
        !          3806:       offset_ptr->var = 0;
        !          3807:     }
        !          3808:   if (where_pad == upward
        !          3809:       && (TREE_CODE (sizetree) != INTEGER_CST
        !          3810:          || ((TREE_INT_CST_LOW (sizetree) * BITS_PER_UNIT) % PARM_BOUNDARY)))
        !          3811:     sizetree = round_up (sizetree, PARM_BOUNDARY / BITS_PER_UNIT);
        !          3812:   SUB_PARM_SIZE (*offset_ptr, sizetree);
        !          3813:   if (where_pad != downward)
        !          3814:     pad_to_arg_alignment (offset_ptr, boundary);
        !          3815:   if (initial_offset_ptr->var)
        !          3816:     {
        !          3817:       arg_size_ptr->var = size_binop (MINUS_EXPR,
        !          3818:                                      size_binop (MINUS_EXPR,
        !          3819:                                                  integer_zero_node,
        !          3820:                                                  initial_offset_ptr->var),
        !          3821:                                      offset_ptr->var);
        !          3822:     }
        !          3823:   else
        !          3824:     {
        !          3825:       arg_size_ptr->constant = (- initial_offset_ptr->constant -
        !          3826:                                offset_ptr->constant); 
        !          3827:     }
        !          3828: /*  ADD_PARM_SIZE (*arg_size_ptr, sizetree); */
        !          3829:   if (where_pad == downward)
        !          3830:     pad_below (arg_size_ptr, passed_mode, sizetree);
        !          3831: #else /* !ARGS_GROW_DOWNWARD */
        !          3832:   pad_to_arg_alignment (initial_offset_ptr, boundary);
        !          3833:   *offset_ptr = *initial_offset_ptr;
        !          3834: 
        !          3835: #ifdef PUSH_ROUNDING
        !          3836:   if (passed_mode != BLKmode)
        !          3837:     sizetree = size_int (PUSH_ROUNDING (TREE_INT_CST_LOW (sizetree)));
        !          3838: #endif
        !          3839: 
        !          3840:   if (where_pad != none
        !          3841:       && (TREE_CODE (sizetree) != INTEGER_CST
        !          3842:          || ((TREE_INT_CST_LOW (sizetree) * BITS_PER_UNIT) % PARM_BOUNDARY)))
        !          3843:     sizetree = round_up (sizetree, PARM_BOUNDARY / BITS_PER_UNIT);
        !          3844: 
        !          3845:   /* This must be done after rounding sizetree, so that it will subtract
        !          3846:      the same value that we explicitly add below.  */
        !          3847:   if (where_pad == downward)
        !          3848:     pad_below (offset_ptr, passed_mode, sizetree);
        !          3849:   ADD_PARM_SIZE (*arg_size_ptr, sizetree);
        !          3850: #endif /* ARGS_GROW_DOWNWARD */
        !          3851: }
        !          3852: 
        !          3853: /* Round the stack offset in *OFFSET_PTR up to a multiple of BOUNDARY.
        !          3854:    BOUNDARY is measured in bits, but must be a multiple of a storage unit.  */
        !          3855: 
        !          3856: static void
        !          3857: pad_to_arg_alignment (offset_ptr, boundary)
        !          3858:      struct args_size *offset_ptr;
        !          3859:      int boundary;
        !          3860: {
        !          3861:   int boundary_in_bytes = boundary / BITS_PER_UNIT;
        !          3862:   
        !          3863:   if (boundary > BITS_PER_UNIT)
        !          3864:     {
        !          3865:       if (offset_ptr->var)
        !          3866:        {
        !          3867:          offset_ptr->var  =
        !          3868: #ifdef ARGS_GROW_DOWNWARD
        !          3869:            round_down 
        !          3870: #else
        !          3871:            round_up
        !          3872: #endif
        !          3873:              (ARGS_SIZE_TREE (*offset_ptr),
        !          3874:               boundary / BITS_PER_UNIT);
        !          3875:          offset_ptr->constant = 0; /*?*/
        !          3876:        }
        !          3877:       else
        !          3878:        offset_ptr->constant =
        !          3879: #ifdef ARGS_GROW_DOWNWARD
        !          3880:          FLOOR_ROUND (offset_ptr->constant, boundary_in_bytes);
        !          3881: #else
        !          3882:          CEIL_ROUND (offset_ptr->constant, boundary_in_bytes);
        !          3883: #endif
        !          3884:     }
        !          3885: }
        !          3886: 
        !          3887: static void
        !          3888: pad_below (offset_ptr, passed_mode, sizetree)
        !          3889:      struct args_size *offset_ptr;
        !          3890:      enum machine_mode passed_mode;
        !          3891:      tree sizetree;
        !          3892: {
        !          3893:   if (passed_mode != BLKmode)
        !          3894:     {
        !          3895:       if (GET_MODE_BITSIZE (passed_mode) % PARM_BOUNDARY)
        !          3896:        offset_ptr->constant
        !          3897:          += (((GET_MODE_BITSIZE (passed_mode) + PARM_BOUNDARY - 1)
        !          3898:               / PARM_BOUNDARY * PARM_BOUNDARY / BITS_PER_UNIT)
        !          3899:              - GET_MODE_SIZE (passed_mode));
        !          3900:     }
        !          3901:   else
        !          3902:     {
        !          3903:       if (TREE_CODE (sizetree) != INTEGER_CST
        !          3904:          || (TREE_INT_CST_LOW (sizetree) * BITS_PER_UNIT) % PARM_BOUNDARY)
        !          3905:        {
        !          3906:          /* Round the size up to multiple of PARM_BOUNDARY bits.  */
        !          3907:          tree s2 = round_up (sizetree, PARM_BOUNDARY / BITS_PER_UNIT);
        !          3908:          /* Add it in.  */
        !          3909:          ADD_PARM_SIZE (*offset_ptr, s2);
        !          3910:          SUB_PARM_SIZE (*offset_ptr, sizetree);
        !          3911:        }
        !          3912:     }
        !          3913: }
        !          3914: 
        !          3915: static tree
        !          3916: round_down (value, divisor)
        !          3917:      tree value;
        !          3918:      int divisor;
        !          3919: {
        !          3920:   return size_binop (MULT_EXPR,
        !          3921:                     size_binop (FLOOR_DIV_EXPR, value, size_int (divisor)),
        !          3922:                     size_int (divisor));
        !          3923: }
        !          3924: 
        !          3925: /* Walk the tree of blocks describing the binding levels within a function
        !          3926:    and warn about uninitialized variables.
        !          3927:    This is done after calling flow_analysis and before global_alloc
        !          3928:    clobbers the pseudo-regs to hard regs.  */
        !          3929: 
        !          3930: void
        !          3931: uninitialized_vars_warning (block)
        !          3932:      tree block;
        !          3933: {
        !          3934:   register tree decl, sub;
        !          3935:   for (decl = BLOCK_VARS (block); decl; decl = TREE_CHAIN (decl))
        !          3936:     {
        !          3937:       if (TREE_CODE (decl) == VAR_DECL
        !          3938:          /* These warnings are unreliable for and aggregates
        !          3939:             because assigning the fields one by one can fail to convince
        !          3940:             flow.c that the entire aggregate was initialized.
        !          3941:             Unions are troublesome because members may be shorter.  */
        !          3942:          && TREE_CODE (TREE_TYPE (decl)) != RECORD_TYPE
        !          3943:          && TREE_CODE (TREE_TYPE (decl)) != UNION_TYPE
        !          3944:          && TREE_CODE (TREE_TYPE (decl)) != QUAL_UNION_TYPE
        !          3945:          && TREE_CODE (TREE_TYPE (decl)) != ARRAY_TYPE
        !          3946:          && DECL_RTL (decl) != 0
        !          3947:          && GET_CODE (DECL_RTL (decl)) == REG
        !          3948:          && regno_uninitialized (REGNO (DECL_RTL (decl))))
        !          3949:        warning_with_decl (decl,
        !          3950:                           "`%s' may be used uninitialized in this function");
        !          3951:       if (TREE_CODE (decl) == VAR_DECL
        !          3952:          && DECL_RTL (decl) != 0
        !          3953:          && GET_CODE (DECL_RTL (decl)) == REG
        !          3954:          && regno_clobbered_at_setjmp (REGNO (DECL_RTL (decl))))
        !          3955:        warning_with_decl (decl,
        !          3956:                           "variable `%s' may be clobbered by `longjmp' or `vfork'");
        !          3957:     }
        !          3958:   for (sub = BLOCK_SUBBLOCKS (block); sub; sub = TREE_CHAIN (sub))
        !          3959:     uninitialized_vars_warning (sub);
        !          3960: }
        !          3961: 
        !          3962: /* Do the appropriate part of uninitialized_vars_warning
        !          3963:    but for arguments instead of local variables.  */
        !          3964: 
        !          3965: void
        !          3966: setjmp_args_warning (block)
        !          3967:      tree block;
        !          3968: {
        !          3969:   register tree decl;
        !          3970:   for (decl = DECL_ARGUMENTS (current_function_decl);
        !          3971:        decl; decl = TREE_CHAIN (decl))
        !          3972:     if (DECL_RTL (decl) != 0
        !          3973:        && GET_CODE (DECL_RTL (decl)) == REG
        !          3974:        && regno_clobbered_at_setjmp (REGNO (DECL_RTL (decl))))
        !          3975:       warning_with_decl (decl, "argument `%s' may be clobbered by `longjmp' or `vfork'");
        !          3976: }
        !          3977: 
        !          3978: /* If this function call setjmp, put all vars into the stack
        !          3979:    unless they were declared `register'.  */
        !          3980: 
        !          3981: void
        !          3982: setjmp_protect (block)
        !          3983:      tree block;
        !          3984: {
        !          3985:   register tree decl, sub;
        !          3986:   for (decl = BLOCK_VARS (block); decl; decl = TREE_CHAIN (decl))
        !          3987:     if ((TREE_CODE (decl) == VAR_DECL
        !          3988:         || TREE_CODE (decl) == PARM_DECL)
        !          3989:        && DECL_RTL (decl) != 0
        !          3990:        && GET_CODE (DECL_RTL (decl)) == REG
        !          3991:        /* If this variable came from an inline function, it must be
        !          3992:           that it's life doesn't overlap the setjmp.  If there was a
        !          3993:           setjmp in the function, it would already be in memory.  We
        !          3994:           must exclude such variable because their DECL_RTL might be
        !          3995:           set to strange things such as virtual_stack_vars_rtx.  */
        !          3996:        && ! DECL_FROM_INLINE (decl)
        !          3997:        && (
        !          3998: #ifdef NON_SAVING_SETJMP
        !          3999:            /* If longjmp doesn't restore the registers,
        !          4000:               don't put anything in them.  */
        !          4001:            NON_SAVING_SETJMP
        !          4002:            ||
        !          4003: #endif
        !          4004:            ! DECL_REGISTER (decl)))
        !          4005:       put_var_into_stack (decl);
        !          4006:   for (sub = BLOCK_SUBBLOCKS (block); sub; sub = TREE_CHAIN (sub))
        !          4007:     setjmp_protect (sub);
        !          4008: }
        !          4009: 
        !          4010: /* Like the previous function, but for args instead of local variables.  */
        !          4011: 
        !          4012: void
        !          4013: setjmp_protect_args ()
        !          4014: {
        !          4015:   register tree decl, sub;
        !          4016:   for (decl = DECL_ARGUMENTS (current_function_decl);
        !          4017:        decl; decl = TREE_CHAIN (decl))
        !          4018:     if ((TREE_CODE (decl) == VAR_DECL
        !          4019:         || TREE_CODE (decl) == PARM_DECL)
        !          4020:        && DECL_RTL (decl) != 0
        !          4021:        && GET_CODE (DECL_RTL (decl)) == REG
        !          4022:        && (
        !          4023:            /* If longjmp doesn't restore the registers,
        !          4024:               don't put anything in them.  */
        !          4025: #ifdef NON_SAVING_SETJMP
        !          4026:            NON_SAVING_SETJMP
        !          4027:            ||
        !          4028: #endif
        !          4029:            ! DECL_REGISTER (decl)))
        !          4030:       put_var_into_stack (decl);
        !          4031: }
        !          4032: 
        !          4033: /* Return the context-pointer register corresponding to DECL,
        !          4034:    or 0 if it does not need one.  */
        !          4035: 
        !          4036: rtx
        !          4037: lookup_static_chain (decl)
        !          4038:      tree decl;
        !          4039: {
        !          4040:   tree context = decl_function_context (decl);
        !          4041:   tree link;
        !          4042: 
        !          4043:   if (context == 0)
        !          4044:     return 0;
        !          4045:   
        !          4046:   /* We treat inline_function_decl as an alias for the current function
        !          4047:      because that is the inline function whose vars, types, etc.
        !          4048:      are being merged into the current function.
        !          4049:      See expand_inline_function.  */
        !          4050:   if (context == current_function_decl || context == inline_function_decl)
        !          4051:     return virtual_stack_vars_rtx;
        !          4052: 
        !          4053:   for (link = context_display; link; link = TREE_CHAIN (link))
        !          4054:     if (TREE_PURPOSE (link) == context)
        !          4055:       return RTL_EXPR_RTL (TREE_VALUE (link));
        !          4056: 
        !          4057:   abort ();
        !          4058: }
        !          4059: 
        !          4060: /* Convert a stack slot address ADDR for variable VAR
        !          4061:    (from a containing function)
        !          4062:    into an address valid in this function (using a static chain).  */
        !          4063: 
        !          4064: rtx
        !          4065: fix_lexical_addr (addr, var)
        !          4066:      rtx addr;
        !          4067:      tree var;
        !          4068: {
        !          4069:   rtx basereg;
        !          4070:   int displacement;
        !          4071:   tree context = decl_function_context (var);
        !          4072:   struct function *fp;
        !          4073:   rtx base = 0;
        !          4074: 
        !          4075:   /* If this is the present function, we need not do anything.  */
        !          4076:   if (context == current_function_decl || context == inline_function_decl)
        !          4077:     return addr;
        !          4078: 
        !          4079:   for (fp = outer_function_chain; fp; fp = fp->next)
        !          4080:     if (fp->decl == context)
        !          4081:       break;
        !          4082: 
        !          4083:   if (fp == 0)
        !          4084:     abort ();
        !          4085: 
        !          4086:   /* Decode given address as base reg plus displacement.  */
        !          4087:   if (GET_CODE (addr) == REG)
        !          4088:     basereg = addr, displacement = 0;
        !          4089:   else if (GET_CODE (addr) == PLUS && GET_CODE (XEXP (addr, 1)) == CONST_INT)
        !          4090:     basereg = XEXP (addr, 0), displacement = INTVAL (XEXP (addr, 1));
        !          4091:   else
        !          4092:     abort ();
        !          4093: 
        !          4094:   /* We accept vars reached via the containing function's
        !          4095:      incoming arg pointer and via its stack variables pointer.  */
        !          4096:   if (basereg == fp->internal_arg_pointer)
        !          4097:     {
        !          4098:       /* If reached via arg pointer, get the arg pointer value
        !          4099:         out of that function's stack frame.
        !          4100: 
        !          4101:         There are two cases:  If a separate ap is needed, allocate a
        !          4102:         slot in the outer function for it and dereference it that way.
        !          4103:         This is correct even if the real ap is actually a pseudo.
        !          4104:         Otherwise, just adjust the offset from the frame pointer to
        !          4105:         compensate.  */
        !          4106: 
        !          4107: #ifdef NEED_SEPARATE_AP
        !          4108:       rtx addr;
        !          4109: 
        !          4110:       if (fp->arg_pointer_save_area == 0)
        !          4111:        fp->arg_pointer_save_area
        !          4112:          = assign_outer_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0, fp);
        !          4113: 
        !          4114:       addr = fix_lexical_addr (XEXP (fp->arg_pointer_save_area, 0), var);
        !          4115:       addr = memory_address (Pmode, addr);
        !          4116: 
        !          4117:       base = copy_to_reg (gen_rtx (MEM, Pmode, addr));
        !          4118: #else
        !          4119:       displacement += (FIRST_PARM_OFFSET (context) - STARTING_FRAME_OFFSET);
        !          4120:       base = lookup_static_chain (var);
        !          4121: #endif
        !          4122:     }
        !          4123: 
        !          4124:   else if (basereg == virtual_stack_vars_rtx)
        !          4125:     {
        !          4126:       /* This is the same code as lookup_static_chain, duplicated here to
        !          4127:         avoid an extra call to decl_function_context.  */
        !          4128:       tree link;
        !          4129: 
        !          4130:       for (link = context_display; link; link = TREE_CHAIN (link))
        !          4131:        if (TREE_PURPOSE (link) == context)
        !          4132:          {
        !          4133:            base = RTL_EXPR_RTL (TREE_VALUE (link));
        !          4134:            break;
        !          4135:          }
        !          4136:     }
        !          4137: 
        !          4138:   if (base == 0)
        !          4139:     abort ();
        !          4140: 
        !          4141:   /* Use same offset, relative to appropriate static chain or argument
        !          4142:      pointer.  */
        !          4143:   return plus_constant (base, displacement);
        !          4144: }
        !          4145: 
        !          4146: /* Return the address of the trampoline for entering nested fn FUNCTION.
        !          4147:    If necessary, allocate a trampoline (in the stack frame)
        !          4148:    and emit rtl to initialize its contents (at entry to this function).  */
        !          4149: 
        !          4150: rtx
        !          4151: trampoline_address (function)
        !          4152:      tree function;
        !          4153: {
        !          4154:   tree link;
        !          4155:   tree rtlexp;
        !          4156:   rtx tramp;
        !          4157:   struct function *fp;
        !          4158:   tree fn_context;
        !          4159: 
        !          4160:   /* Find an existing trampoline and return it.  */
        !          4161:   for (link = trampoline_list; link; link = TREE_CHAIN (link))
        !          4162:     if (TREE_PURPOSE (link) == function)
        !          4163:       return XEXP (RTL_EXPR_RTL (TREE_VALUE (link)), 0);
        !          4164:   for (fp = outer_function_chain; fp; fp = fp->next)
        !          4165:     for (link = fp->trampoline_list; link; link = TREE_CHAIN (link))
        !          4166:       if (TREE_PURPOSE (link) == function)
        !          4167:        {
        !          4168:          tramp = fix_lexical_addr (XEXP (RTL_EXPR_RTL (TREE_VALUE (link)), 0),
        !          4169:                                    function);
        !          4170:          return round_trampoline_addr (tramp);
        !          4171:        }
        !          4172: 
        !          4173:   /* None exists; we must make one.  */
        !          4174: 
        !          4175:   /* Find the `struct function' for the function containing FUNCTION.  */
        !          4176:   fp = 0;
        !          4177:   fn_context = decl_function_context (function);
        !          4178:   if (fn_context != current_function_decl)
        !          4179:     for (fp = outer_function_chain; fp; fp = fp->next)
        !          4180:       if (fp->decl == fn_context)
        !          4181:        break;
        !          4182: 
        !          4183:   /* Allocate run-time space for this trampoline
        !          4184:      (usually in the defining function's stack frame).  */
        !          4185: #ifdef ALLOCATE_TRAMPOLINE
        !          4186:   tramp = ALLOCATE_TRAMPOLINE (fp);
        !          4187: #else
        !          4188:   /* If rounding needed, allocate extra space
        !          4189:      to ensure we have TRAMPOLINE_SIZE bytes left after rounding up.  */
        !          4190: #ifdef TRAMPOLINE_ALIGNMENT
        !          4191: #define TRAMPOLINE_REAL_SIZE (TRAMPOLINE_SIZE + TRAMPOLINE_ALIGNMENT - 1)
        !          4192: #else
        !          4193: #define TRAMPOLINE_REAL_SIZE (TRAMPOLINE_SIZE)
        !          4194: #endif
        !          4195:   if (fp != 0)
        !          4196:     tramp = assign_outer_stack_local (BLKmode, TRAMPOLINE_REAL_SIZE, 0, fp);
        !          4197:   else
        !          4198:     tramp = assign_stack_local (BLKmode, TRAMPOLINE_REAL_SIZE, 0);
        !          4199: #endif
        !          4200: 
        !          4201:   /* Record the trampoline for reuse and note it for later initialization
        !          4202:      by expand_function_end.  */
        !          4203:   if (fp != 0)
        !          4204:     {
        !          4205:       push_obstacks (fp->function_maybepermanent_obstack,
        !          4206:                     fp->function_maybepermanent_obstack);
        !          4207:       rtlexp = make_node (RTL_EXPR);
        !          4208:       RTL_EXPR_RTL (rtlexp) = tramp;
        !          4209:       fp->trampoline_list = tree_cons (function, rtlexp, fp->trampoline_list);
        !          4210:       pop_obstacks ();
        !          4211:     }
        !          4212:   else
        !          4213:     {
        !          4214:       /* Make the RTL_EXPR node temporary, not momentary, so that the
        !          4215:         trampoline_list doesn't become garbage.  */
        !          4216:       int momentary = suspend_momentary ();
        !          4217:       rtlexp = make_node (RTL_EXPR);
        !          4218:       resume_momentary (momentary);
        !          4219: 
        !          4220:       RTL_EXPR_RTL (rtlexp) = tramp;
        !          4221:       trampoline_list = tree_cons (function, rtlexp, trampoline_list);
        !          4222:     }
        !          4223: 
        !          4224:   tramp = fix_lexical_addr (XEXP (tramp, 0), function);
        !          4225:   return round_trampoline_addr (tramp);
        !          4226: }
        !          4227: 
        !          4228: /* Given a trampoline address,
        !          4229:    round it to multiple of TRAMPOLINE_ALIGNMENT.  */
        !          4230: 
        !          4231: static rtx
        !          4232: round_trampoline_addr (tramp)
        !          4233:      rtx tramp;
        !          4234: {
        !          4235: #ifdef TRAMPOLINE_ALIGNMENT
        !          4236:   /* Round address up to desired boundary.  */
        !          4237:   rtx temp = gen_reg_rtx (Pmode);
        !          4238:   temp = expand_binop (Pmode, add_optab, tramp,
        !          4239:                       GEN_INT (TRAMPOLINE_ALIGNMENT - 1),
        !          4240:                       temp, 0, OPTAB_LIB_WIDEN);
        !          4241:   tramp = expand_binop (Pmode, and_optab, temp,
        !          4242:                        GEN_INT (- TRAMPOLINE_ALIGNMENT),
        !          4243:                        temp, 0, OPTAB_LIB_WIDEN);
        !          4244: #endif
        !          4245:   return tramp;
        !          4246: }
        !          4247: 
        !          4248: /* The functions identify_blocks and reorder_blocks provide a way to
        !          4249:    reorder the tree of BLOCK nodes, for optimizers that reshuffle or
        !          4250:    duplicate portions of the RTL code.  Call identify_blocks before
        !          4251:    changing the RTL, and call reorder_blocks after.  */
        !          4252: 
        !          4253: static int all_blocks ();
        !          4254: static tree blocks_nreverse ();
        !          4255: 
        !          4256: /* Put all this function's BLOCK nodes into a vector, and return it.
        !          4257:    Also store in each NOTE for the beginning or end of a block
        !          4258:    the index of that block in the vector.
        !          4259:    The arguments are TOP_BLOCK, the top-level block of the function,
        !          4260:    and INSNS, the insn chain of the function.  */
        !          4261: 
        !          4262: tree *
        !          4263: identify_blocks (top_block, insns)
        !          4264:      tree top_block;
        !          4265:      rtx insns;
        !          4266: {
        !          4267:   int n_blocks;
        !          4268:   tree *block_vector;
        !          4269:   int *block_stack;
        !          4270:   int depth = 0;
        !          4271:   int next_block_number = 0;
        !          4272:   int current_block_number = 0;
        !          4273:   rtx insn;
        !          4274: 
        !          4275:   if (top_block == 0)
        !          4276:     return 0;
        !          4277: 
        !          4278:   n_blocks = all_blocks (top_block, 0);
        !          4279:   block_vector = (tree *) xmalloc (n_blocks * sizeof (tree));
        !          4280:   block_stack = (int *) alloca (n_blocks * sizeof (int));
        !          4281: 
        !          4282:   all_blocks (top_block, block_vector);
        !          4283: 
        !          4284:   for (insn = insns; insn; insn = NEXT_INSN (insn))
        !          4285:     if (GET_CODE (insn) == NOTE)
        !          4286:       {
        !          4287:        if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG)
        !          4288:          {
        !          4289:            block_stack[depth++] = current_block_number;
        !          4290:            current_block_number = next_block_number;
        !          4291:            NOTE_BLOCK_NUMBER (insn) =  next_block_number++;
        !          4292:          }
        !          4293:        if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END)
        !          4294:          {
        !          4295:            current_block_number = block_stack[--depth];
        !          4296:            NOTE_BLOCK_NUMBER (insn) = current_block_number;
        !          4297:          }
        !          4298:       }
        !          4299: 
        !          4300:   return block_vector;
        !          4301: }
        !          4302: 
        !          4303: /* Given BLOCK_VECTOR which was returned by identify_blocks,
        !          4304:    and a revised instruction chain, rebuild the tree structure
        !          4305:    of BLOCK nodes to correspond to the new order of RTL.
        !          4306:    The new block tree is inserted below TOP_BLOCK.
        !          4307:    Returns the current top-level block.  */
        !          4308: 
        !          4309: tree
        !          4310: reorder_blocks (block_vector, top_block, insns)
        !          4311:      tree *block_vector;
        !          4312:      tree top_block;
        !          4313:      rtx insns;
        !          4314: {
        !          4315:   tree current_block = top_block;
        !          4316:   rtx insn;
        !          4317: 
        !          4318:   if (block_vector == 0)
        !          4319:     return top_block;
        !          4320: 
        !          4321:   /* Prune the old tree away, so that it doesn't get in the way.  */
        !          4322:   BLOCK_SUBBLOCKS (current_block) = 0;
        !          4323: 
        !          4324:   for (insn = insns; insn; insn = NEXT_INSN (insn))
        !          4325:     if (GET_CODE (insn) == NOTE)
        !          4326:       {
        !          4327:        if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG)
        !          4328:          {
        !          4329:            tree block = block_vector[NOTE_BLOCK_NUMBER (insn)];
        !          4330:            /* If we have seen this block before, copy it.  */
        !          4331:            if (TREE_ASM_WRITTEN (block))
        !          4332:              block = copy_node (block);
        !          4333:            BLOCK_SUBBLOCKS (block) = 0;
        !          4334:            TREE_ASM_WRITTEN (block) = 1;
        !          4335:            BLOCK_SUPERCONTEXT (block) = current_block; 
        !          4336:            BLOCK_CHAIN (block) = BLOCK_SUBBLOCKS (current_block);
        !          4337:            BLOCK_SUBBLOCKS (current_block) = block;
        !          4338:            current_block = block;
        !          4339:            NOTE_SOURCE_FILE (insn) = 0;
        !          4340:          }
        !          4341:        if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END)
        !          4342:          {
        !          4343:            BLOCK_SUBBLOCKS (current_block)
        !          4344:              = blocks_nreverse (BLOCK_SUBBLOCKS (current_block));
        !          4345:            current_block = BLOCK_SUPERCONTEXT (current_block);
        !          4346:            NOTE_SOURCE_FILE (insn) = 0;
        !          4347:          }
        !          4348:       }
        !          4349: 
        !          4350:   return current_block;
        !          4351: }
        !          4352: 
        !          4353: /* Reverse the order of elements in the chain T of blocks,
        !          4354:    and return the new head of the chain (old last element).  */
        !          4355: 
        !          4356: static tree
        !          4357: blocks_nreverse (t)
        !          4358:      tree t;
        !          4359: {
        !          4360:   register tree prev = 0, decl, next;
        !          4361:   for (decl = t; decl; decl = next)
        !          4362:     {
        !          4363:       next = BLOCK_CHAIN (decl);
        !          4364:       BLOCK_CHAIN (decl) = prev;
        !          4365:       prev = decl;
        !          4366:     }
        !          4367:   return prev;
        !          4368: }
        !          4369: 
        !          4370: /* Count the subblocks of BLOCK, and list them all into the vector VECTOR.
        !          4371:    Also clear TREE_ASM_WRITTEN in all blocks.  */
        !          4372: 
        !          4373: static int
        !          4374: all_blocks (block, vector)
        !          4375:      tree block;
        !          4376:      tree *vector;
        !          4377: {
        !          4378:   int n_blocks = 1;
        !          4379:   tree subblocks; 
        !          4380: 
        !          4381:   TREE_ASM_WRITTEN (block) = 0;
        !          4382:   /* Record this block.  */
        !          4383:   if (vector)
        !          4384:     vector[0] = block;
        !          4385: 
        !          4386:   /* Record the subblocks, and their subblocks.  */
        !          4387:   for (subblocks = BLOCK_SUBBLOCKS (block);
        !          4388:        subblocks; subblocks = BLOCK_CHAIN (subblocks))
        !          4389:     n_blocks += all_blocks (subblocks, vector ? vector + n_blocks : 0);
        !          4390: 
        !          4391:   return n_blocks;
        !          4392: }
        !          4393: 
        !          4394: /* Build bytecode call descriptor for function SUBR. */
        !          4395: rtx
        !          4396: bc_build_calldesc (subr)
        !          4397:   tree subr;
        !          4398: {
        !          4399:   tree calldesc = 0, arg;
        !          4400:   int nargs = 0;
        !          4401: 
        !          4402:   /* Build the argument description vector in reverse order.  */
        !          4403:   DECL_ARGUMENTS (subr) = nreverse (DECL_ARGUMENTS (subr));
        !          4404:   nargs = 0;
        !          4405: 
        !          4406:   for (arg = DECL_ARGUMENTS (subr); arg; arg = TREE_CHAIN (arg))
        !          4407:     {
        !          4408:       ++nargs;
        !          4409: 
        !          4410:       calldesc = tree_cons ((tree) 0, size_in_bytes (TREE_TYPE (arg)), calldesc);
        !          4411:       calldesc = tree_cons ((tree) 0, bc_runtime_type_code (TREE_TYPE (arg)), calldesc);
        !          4412:     }
        !          4413: 
        !          4414:   DECL_ARGUMENTS (subr) = nreverse (DECL_ARGUMENTS (subr));
        !          4415: 
        !          4416:   /* Prepend the function's return type.  */
        !          4417:   calldesc = tree_cons ((tree) 0,
        !          4418:                        size_in_bytes (TREE_TYPE (TREE_TYPE (subr))),
        !          4419:                        calldesc);
        !          4420: 
        !          4421:   calldesc = tree_cons ((tree) 0,
        !          4422:                        bc_runtime_type_code (TREE_TYPE (TREE_TYPE (subr))),
        !          4423:                        calldesc);
        !          4424: 
        !          4425:   /* Prepend the arg count.  */
        !          4426:   calldesc = tree_cons ((tree) 0, build_int_2 (nargs, 0), calldesc);
        !          4427: 
        !          4428:   /* Output the call description vector and get its address.  */
        !          4429:   calldesc = build_nt (CONSTRUCTOR, (tree) 0, calldesc);
        !          4430:   TREE_TYPE (calldesc) = build_array_type (integer_type_node,
        !          4431:                                           build_index_type (build_int_2 (nargs * 2, 0)));
        !          4432: 
        !          4433:   return output_constant_def (calldesc);
        !          4434: }
        !          4435: 
        !          4436: 
        !          4437: /* Generate RTL for the start of the function SUBR (a FUNCTION_DECL tree node)
        !          4438:    and initialize static variables for generating RTL for the statements
        !          4439:    of the function.  */
        !          4440: 
        !          4441: void
        !          4442: init_function_start (subr, filename, line)
        !          4443:      tree subr;
        !          4444:      char *filename;
        !          4445:      int line;
        !          4446: {
        !          4447:   char *junk;
        !          4448: 
        !          4449:   if (output_bytecode)
        !          4450:     {
        !          4451:       this_function_decl = subr;
        !          4452:       this_function_calldesc = bc_build_calldesc (subr);
        !          4453:       local_vars_size = 0;
        !          4454:       stack_depth = 0;
        !          4455:       max_stack_depth = 0;
        !          4456:       stmt_expr_depth = 0;
        !          4457:       return;
        !          4458:     }
        !          4459: 
        !          4460:   init_stmt_for_function ();
        !          4461: 
        !          4462:   cse_not_expected = ! optimize;
        !          4463: 
        !          4464:   /* Caller save not needed yet.  */
        !          4465:   caller_save_needed = 0;
        !          4466: 
        !          4467:   /* No stack slots have been made yet.  */
        !          4468:   stack_slot_list = 0;
        !          4469: 
        !          4470:   /* There is no stack slot for handling nonlocal gotos.  */
        !          4471:   nonlocal_goto_handler_slot = 0;
        !          4472:   nonlocal_goto_stack_level = 0;
        !          4473: 
        !          4474:   /* No labels have been declared for nonlocal use.  */
        !          4475:   nonlocal_labels = 0;
        !          4476: 
        !          4477:   /* No function calls so far in this function.  */
        !          4478:   function_call_count = 0;
        !          4479: 
        !          4480:   /* No parm regs have been allocated.
        !          4481:      (This is important for output_inline_function.)  */
        !          4482:   max_parm_reg = LAST_VIRTUAL_REGISTER + 1;
        !          4483: 
        !          4484:   /* Initialize the RTL mechanism.  */
        !          4485:   init_emit ();
        !          4486: 
        !          4487:   /* Initialize the queue of pending postincrement and postdecrements,
        !          4488:      and some other info in expr.c.  */
        !          4489:   init_expr ();
        !          4490: 
        !          4491:   /* We haven't done register allocation yet.  */
        !          4492:   reg_renumber = 0;
        !          4493: 
        !          4494:   init_const_rtx_hash_table ();
        !          4495: 
        !          4496:   current_function_name = (*decl_printable_name) (subr, &junk);
        !          4497: 
        !          4498:   /* Nonzero if this is a nested function that uses a static chain.  */
        !          4499: 
        !          4500:   current_function_needs_context
        !          4501:     = (decl_function_context (current_function_decl) != 0);
        !          4502: 
        !          4503:   /* Set if a call to setjmp is seen.  */
        !          4504:   current_function_calls_setjmp = 0;
        !          4505: 
        !          4506:   /* Set if a call to longjmp is seen.  */
        !          4507:   current_function_calls_longjmp = 0;
        !          4508: 
        !          4509:   current_function_calls_alloca = 0;
        !          4510:   current_function_has_nonlocal_label = 0;
        !          4511:   current_function_has_nonlocal_goto = 0;
        !          4512:   current_function_contains_functions = 0;
        !          4513: 
        !          4514:   current_function_returns_pcc_struct = 0;
        !          4515:   current_function_returns_struct = 0;
        !          4516:   current_function_epilogue_delay_list = 0;
        !          4517:   current_function_uses_const_pool = 0;
        !          4518:   current_function_uses_pic_offset_table = 0;
        !          4519: 
        !          4520:   /* We have not yet needed to make a label to jump to for tail-recursion.  */
        !          4521:   tail_recursion_label = 0;
        !          4522: 
        !          4523:   /* We haven't had a need to make a save area for ap yet.  */
        !          4524: 
        !          4525:   arg_pointer_save_area = 0;
        !          4526: 
        !          4527:   /* No stack slots allocated yet.  */
        !          4528:   frame_offset = 0;
        !          4529: 
        !          4530:   /* No SAVE_EXPRs in this function yet.  */
        !          4531:   save_expr_regs = 0;
        !          4532: 
        !          4533:   /* No RTL_EXPRs in this function yet.  */
        !          4534:   rtl_expr_chain = 0;
        !          4535: 
        !          4536:   /* We have not allocated any temporaries yet.  */
        !          4537:   temp_slots = 0;
        !          4538:   temp_slot_level = 0;
        !          4539: 
        !          4540:   /* Within function body, compute a type's size as soon it is laid out.  */
        !          4541:   immediate_size_expand++;
        !          4542: 
        !          4543:   /* We haven't made any trampolines for this function yet.  */
        !          4544:   trampoline_list = 0;
        !          4545: 
        !          4546:   init_pending_stack_adjust ();
        !          4547:   inhibit_defer_pop = 0;
        !          4548: 
        !          4549:   current_function_outgoing_args_size = 0;
        !          4550: 
        !          4551:   /* Initialize the insn lengths.  */
        !          4552:   init_insn_lengths ();
        !          4553: 
        !          4554:   /* Prevent ever trying to delete the first instruction of a function.
        !          4555:      Also tell final how to output a linenum before the function prologue.  */
        !          4556:   emit_line_note (filename, line);
        !          4557: 
        !          4558:   /* Make sure first insn is a note even if we don't want linenums.
        !          4559:      This makes sure the first insn will never be deleted.
        !          4560:      Also, final expects a note to appear there.  */
        !          4561:   emit_note (NULL_PTR, NOTE_INSN_DELETED);
        !          4562: 
        !          4563:   /* Set flags used by final.c.  */
        !          4564:   if (aggregate_value_p (DECL_RESULT (subr)))
        !          4565:     {
        !          4566: #ifdef PCC_STATIC_STRUCT_RETURN
        !          4567:       current_function_returns_pcc_struct = 1;
        !          4568: #endif
        !          4569:       current_function_returns_struct = 1;
        !          4570:     }
        !          4571: 
        !          4572:   /* Warn if this value is an aggregate type,
        !          4573:      regardless of which calling convention we are using for it.  */
        !          4574:   if (warn_aggregate_return
        !          4575:       && (TREE_CODE (TREE_TYPE (DECL_RESULT (subr))) == RECORD_TYPE
        !          4576:          || TREE_CODE (TREE_TYPE (DECL_RESULT (subr))) == UNION_TYPE
        !          4577:          || TREE_CODE (TREE_TYPE (DECL_RESULT (subr))) == QUAL_UNION_TYPE
        !          4578:          || TREE_CODE (TREE_TYPE (DECL_RESULT (subr))) == ARRAY_TYPE))
        !          4579:     warning ("function returns an aggregate");
        !          4580: 
        !          4581:   current_function_returns_pointer
        !          4582:     = (TREE_CODE (TREE_TYPE (DECL_RESULT (subr))) == POINTER_TYPE);
        !          4583: 
        !          4584:   /* Indicate that we need to distinguish between the return value of the
        !          4585:      present function and the return value of a function being called.  */
        !          4586:   rtx_equal_function_value_matters = 1;
        !          4587: 
        !          4588:   /* Indicate that we have not instantiated virtual registers yet.  */
        !          4589:   virtuals_instantiated = 0;
        !          4590: 
        !          4591:   /* Indicate we have no need of a frame pointer yet.  */
        !          4592:   frame_pointer_needed = 0;
        !          4593: 
        !          4594:   /* By default assume not varargs.  */
        !          4595:   current_function_varargs = 0;
        !          4596: }
        !          4597: 
        !          4598: /* Indicate that the current function uses extra args
        !          4599:    not explicitly mentioned in the argument list in any fashion.  */
        !          4600: 
        !          4601: void
        !          4602: mark_varargs ()
        !          4603: {
        !          4604:   current_function_varargs = 1;
        !          4605: }
        !          4606: 
        !          4607: /* Expand a call to __main at the beginning of a possible main function.  */
        !          4608: 
        !          4609: void
        !          4610: expand_main_function ()
        !          4611: {
        !          4612:   if (!output_bytecode)
        !          4613:     {
        !          4614:       /* The zero below avoids a possible parse error */
        !          4615:       0;
        !          4616: #if !defined (INIT_SECTION_ASM_OP) || defined (INVOKE__main)
        !          4617: #ifdef NEXT_EXTENSION
        !          4618:       {
        !          4619:        rtx _argv, _argc;
        !          4620:        tree __main_type 
        !          4621:          = build_function_type (void_type, 
        !          4622:                                 tree_cons (0, int_type,
        !          4623:                                            tree_cons (0, pointer_type, 0)));
        !          4624:        
        !          4625:        emit_library_call (gen_rtx (SYMBOL_REF, Pmode, NAME__MAIN), 0,
        !          4626:                           VOIDmode, 0);
        !          4627:       }
        !          4628: #else
        !          4629:       emit_library_call (gen_rtx (SYMBOL_REF, Pmode, NAME__MAIN), 0,
        !          4630:                         VOIDmode, 0);
        !          4631: #endif
        !          4632: #endif /* not INIT_SECTION_ASM_OP or INVOKE__main */
        !          4633:     }
        !          4634: }
        !          4635: 
        !          4636: extern struct obstack permanent_obstack;
        !          4637: 
        !          4638: /* Expand start of bytecode function. See comment at
        !          4639:    expand_function_start below for details. */
        !          4640: 
        !          4641: void
        !          4642: bc_expand_function_start (subr, parms_have_cleanups)
        !          4643:   tree subr;
        !          4644:   int parms_have_cleanups;
        !          4645: {
        !          4646:   char label[20], *name;
        !          4647:   static int nlab;
        !          4648:   tree thisarg;
        !          4649:   int argsz;
        !          4650: 
        !          4651:   if (TREE_PUBLIC (subr))
        !          4652:     bc_globalize_label (IDENTIFIER_POINTER (DECL_NAME (subr)));
        !          4653: 
        !          4654: #ifdef DEBUG_PRINT_CODE
        !          4655:   fprintf (stderr, "\n<func %s>\n", IDENTIFIER_POINTER (DECL_NAME (subr)));
        !          4656: #endif
        !          4657: 
        !          4658:   for (argsz = 0, thisarg = DECL_ARGUMENTS (subr); thisarg; thisarg = TREE_CHAIN (thisarg))
        !          4659:     {
        !          4660:       if (DECL_RTL (thisarg))
        !          4661:        abort ();               /* Should be NULL here I think.  */
        !          4662:       else if (TREE_CONSTANT (DECL_SIZE (thisarg)))
        !          4663:        {
        !          4664:          DECL_RTL (thisarg) = bc_gen_rtx ((char *) 0, argsz, (struct bc_label *) 0);
        !          4665:          argsz += TREE_INT_CST_LOW (DECL_SIZE (thisarg));
        !          4666:        }
        !          4667:       else
        !          4668:        {
        !          4669:          /* Variable-sized objects are pointers to their storage. */
        !          4670:          DECL_RTL (thisarg) = bc_gen_rtx ((char *) 0, argsz, (struct bc_label *) 0);
        !          4671:          argsz += POINTER_SIZE;
        !          4672:        }
        !          4673:     }
        !          4674: 
        !          4675:   bc_begin_function (bc_xstrdup (IDENTIFIER_POINTER (DECL_NAME (subr))));
        !          4676: 
        !          4677:   ASM_GENERATE_INTERNAL_LABEL (label, "LX", nlab);
        !          4678: 
        !          4679:   ++nlab;
        !          4680:   name = (char *) obstack_copy0 (&permanent_obstack, label, strlen (label));
        !          4681:   this_function_callinfo = bc_gen_rtx (name, 0, (struct bc_label *) 0);
        !          4682:   this_function_bytecode =
        !          4683:     bc_emit_trampoline (BYTECODE_LABEL (this_function_callinfo));
        !          4684: }
        !          4685: 
        !          4686: 
        !          4687: /* Expand end of bytecode function. See details the comment of
        !          4688:    expand_function_end(), below. */
        !          4689: 
        !          4690: void
        !          4691: bc_expand_function_end ()
        !          4692: {
        !          4693:   char *ptrconsts;
        !          4694: 
        !          4695:   expand_null_return ();
        !          4696: 
        !          4697:   /* Emit any fixup code. This must be done before the call to
        !          4698:      to BC_END_FUNCTION (), since that will cause the bytecode
        !          4699:      segment to be finished off and closed. */
        !          4700: 
        !          4701:   fixup_gotos (0, 0, 0, 0, 0);
        !          4702: 
        !          4703:   ptrconsts = bc_end_function ();
        !          4704: 
        !          4705:   bc_align_const (2 /* INT_ALIGN */);
        !          4706: 
        !          4707:   /* If this changes also make sure to change bc-interp.h!  */
        !          4708: 
        !          4709:   bc_emit_const_labeldef (BYTECODE_LABEL (this_function_callinfo));
        !          4710:   bc_emit_const ((char *) &max_stack_depth, sizeof max_stack_depth);
        !          4711:   bc_emit_const ((char *) &local_vars_size, sizeof local_vars_size);
        !          4712:   bc_emit_const_labelref (this_function_bytecode, 0);
        !          4713:   bc_emit_const_labelref (ptrconsts, 0);
        !          4714:   bc_emit_const_labelref (BYTECODE_LABEL (this_function_calldesc), 0);
        !          4715: }
        !          4716: 
        !          4717: 
        !          4718: /* Start the RTL for a new function, and set variables used for
        !          4719:    emitting RTL.
        !          4720:    SUBR is the FUNCTION_DECL node.
        !          4721:    PARMS_HAVE_CLEANUPS is nonzero if there are cleanups associated with
        !          4722:    the function's parameters, which must be run at any return statement.  */
        !          4723: 
        !          4724: void
        !          4725: expand_function_start (subr, parms_have_cleanups)
        !          4726:      tree subr;
        !          4727:      int parms_have_cleanups;
        !          4728: {
        !          4729:   register int i;
        !          4730:   tree tem;
        !          4731:   rtx last_ptr;
        !          4732: 
        !          4733:   if (output_bytecode)
        !          4734:     {
        !          4735:       bc_expand_function_start (subr, parms_have_cleanups);
        !          4736:       return;
        !          4737:     }
        !          4738: 
        !          4739:   /* Make sure volatile mem refs aren't considered
        !          4740:      valid operands of arithmetic insns.  */
        !          4741:   init_recog_no_volatile ();
        !          4742: 
        !          4743:   /* If function gets a static chain arg, store it in the stack frame.
        !          4744:      Do this first, so it gets the first stack slot offset.  */
        !          4745:   if (current_function_needs_context)
        !          4746:     {
        !          4747:       last_ptr = assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0);
        !          4748:       emit_move_insn (last_ptr, static_chain_incoming_rtx);
        !          4749:     }
        !          4750: 
        !          4751:   /* If the parameters of this function need cleaning up, get a label
        !          4752:      for the beginning of the code which executes those cleanups.  This must
        !          4753:      be done before doing anything with return_label.  */
        !          4754:   if (parms_have_cleanups)
        !          4755:     cleanup_label = gen_label_rtx ();
        !          4756:   else
        !          4757:     cleanup_label = 0;
        !          4758: 
        !          4759:   /* Make the label for return statements to jump to, if this machine
        !          4760:      does not have a one-instruction return and uses an epilogue,
        !          4761:      or if it returns a structure, or if it has parm cleanups.  */
        !          4762: #ifdef HAVE_return
        !          4763:   if (cleanup_label == 0 && HAVE_return
        !          4764:       && ! current_function_returns_pcc_struct
        !          4765:       && ! (current_function_returns_struct && ! optimize))
        !          4766:     return_label = 0;
        !          4767:   else
        !          4768:     return_label = gen_label_rtx ();
        !          4769: #else
        !          4770:   return_label = gen_label_rtx ();
        !          4771: #endif
        !          4772: 
        !          4773:   /* Initialize rtx used to return the value.  */
        !          4774:   /* Do this before assign_parms so that we copy the struct value address
        !          4775:      before any library calls that assign parms might generate.  */
        !          4776: 
        !          4777:   /* Decide whether to return the value in memory or in a register.  */
        !          4778:   if (aggregate_value_p (DECL_RESULT (subr)))
        !          4779:     {
        !          4780:       /* Returning something that won't go in a register.  */
        !          4781:       register rtx value_address;
        !          4782: 
        !          4783: #ifdef PCC_STATIC_STRUCT_RETURN
        !          4784:       if (current_function_returns_pcc_struct)
        !          4785:        {
        !          4786:          int size = int_size_in_bytes (TREE_TYPE (DECL_RESULT (subr)));
        !          4787:          value_address = assemble_static_space (size);
        !          4788:        }
        !          4789:       else
        !          4790: #endif
        !          4791:        {
        !          4792:          /* Expect to be passed the address of a place to store the value.
        !          4793:             If it is passed as an argument, assign_parms will take care of
        !          4794:             it.  */
        !          4795:          if (struct_value_incoming_rtx)
        !          4796:            {
        !          4797:              value_address = gen_reg_rtx (Pmode);
        !          4798:              emit_move_insn (value_address, struct_value_incoming_rtx);
        !          4799:            }
        !          4800:        }
        !          4801:       if (value_address)
        !          4802:        DECL_RTL (DECL_RESULT (subr))
        !          4803:          = gen_rtx (MEM, DECL_MODE (DECL_RESULT (subr)),
        !          4804:                     value_address);
        !          4805:     }
        !          4806:   else if (DECL_MODE (DECL_RESULT (subr)) == VOIDmode)
        !          4807:     /* If return mode is void, this decl rtl should not be used.  */
        !          4808:     DECL_RTL (DECL_RESULT (subr)) = 0;
        !          4809:   else if (parms_have_cleanups)
        !          4810:     {
        !          4811:       /* If function will end with cleanup code for parms,
        !          4812:         compute the return values into a pseudo reg,
        !          4813:         which we will copy into the true return register
        !          4814:         after the cleanups are done.  */
        !          4815: 
        !          4816:       enum machine_mode mode = DECL_MODE (DECL_RESULT (subr));
        !          4817: #ifdef PROMOTE_FUNCTION_RETURN
        !          4818:       tree type = TREE_TYPE (DECL_RESULT (subr));
        !          4819:       int unsignedp = TREE_UNSIGNED (type);
        !          4820: 
        !          4821:       if (TREE_CODE (type) == INTEGER_TYPE || TREE_CODE (type) == ENUMERAL_TYPE
        !          4822:          || TREE_CODE (type) == BOOLEAN_TYPE || TREE_CODE (type) == CHAR_TYPE
        !          4823:          || TREE_CODE (type) == REAL_TYPE || TREE_CODE (type) == POINTER_TYPE
        !          4824:          || TREE_CODE (type) == OFFSET_TYPE)
        !          4825:        {
        !          4826:          PROMOTE_MODE (mode, unsignedp, type);
        !          4827:        }
        !          4828: #endif
        !          4829: 
        !          4830:       DECL_RTL (DECL_RESULT (subr)) = gen_reg_rtx (mode);
        !          4831:     }
        !          4832:   else
        !          4833:     /* Scalar, returned in a register.  */
        !          4834:     {
        !          4835: #ifdef FUNCTION_OUTGOING_VALUE
        !          4836:       DECL_RTL (DECL_RESULT (subr))
        !          4837:        = FUNCTION_OUTGOING_VALUE (TREE_TYPE (DECL_RESULT (subr)), subr);
        !          4838: #else
        !          4839:       DECL_RTL (DECL_RESULT (subr))
        !          4840:        = FUNCTION_VALUE (TREE_TYPE (DECL_RESULT (subr)), subr);
        !          4841: #endif
        !          4842: 
        !          4843:       /* Mark this reg as the function's return value.  */
        !          4844:       if (GET_CODE (DECL_RTL (DECL_RESULT (subr))) == REG)
        !          4845:        {
        !          4846:          REG_FUNCTION_VALUE_P (DECL_RTL (DECL_RESULT (subr))) = 1;
        !          4847:          /* Needed because we may need to move this to memory
        !          4848:             in case it's a named return value whose address is taken.  */
        !          4849:          DECL_REGISTER (DECL_RESULT (subr)) = 1;
        !          4850:        }
        !          4851:     }
        !          4852: 
        !          4853:   /* Initialize rtx for parameters and local variables.
        !          4854:      In some cases this requires emitting insns.  */
        !          4855: 
        !          4856:   assign_parms (subr, 0);
        !          4857: 
        !          4858:   /* The following was moved from init_function_start.
        !          4859:      The move is supposed to make sdb output more accurate.  */
        !          4860:   /* Indicate the beginning of the function body,
        !          4861:      as opposed to parm setup.  */
        !          4862:   emit_note (NULL_PTR, NOTE_INSN_FUNCTION_BEG);
        !          4863: 
        !          4864:   /* If doing stupid allocation, mark parms as born here.  */
        !          4865: 
        !          4866:   if (GET_CODE (get_last_insn ()) != NOTE)
        !          4867:     emit_note (NULL_PTR, NOTE_INSN_DELETED);
        !          4868:   parm_birth_insn = get_last_insn ();
        !          4869: 
        !          4870:   if (obey_regdecls)
        !          4871:     {
        !          4872:       for (i = LAST_VIRTUAL_REGISTER + 1; i < max_parm_reg; i++)
        !          4873:        use_variable (regno_reg_rtx[i]);
        !          4874: 
        !          4875:       if (current_function_internal_arg_pointer != virtual_incoming_args_rtx)
        !          4876:        use_variable (current_function_internal_arg_pointer);
        !          4877:     }
        !          4878: 
        !          4879:   /* Fetch static chain values for containing functions.  */
        !          4880:   tem = decl_function_context (current_function_decl);
        !          4881:   /* If not doing stupid register allocation, then start off with the static
        !          4882:      chain pointer in a pseudo register.  Otherwise, we use the stack
        !          4883:      address that was generated above.  */
        !          4884:   if (tem && ! obey_regdecls)
        !          4885:     last_ptr = copy_to_reg (static_chain_incoming_rtx);
        !          4886:   context_display = 0;
        !          4887:   while (tem)
        !          4888:     {
        !          4889:       tree rtlexp = make_node (RTL_EXPR);
        !          4890: 
        !          4891:       RTL_EXPR_RTL (rtlexp) = last_ptr;
        !          4892:       context_display = tree_cons (tem, rtlexp, context_display);
        !          4893:       tem = decl_function_context (tem);
        !          4894:       if (tem == 0)
        !          4895:        break;
        !          4896:       /* Chain thru stack frames, assuming pointer to next lexical frame
        !          4897:         is found at the place we always store it.  */
        !          4898: #ifdef FRAME_GROWS_DOWNWARD
        !          4899:       last_ptr = plus_constant (last_ptr, - GET_MODE_SIZE (Pmode));
        !          4900: #endif
        !          4901:       last_ptr = copy_to_reg (gen_rtx (MEM, Pmode,
        !          4902:                                       memory_address (Pmode, last_ptr)));
        !          4903: 
        !          4904:       /* If we are not optimizing, ensure that we know that this
        !          4905:         piece of context is live over the entire function.  */
        !          4906:       if (! optimize)
        !          4907:        save_expr_regs = gen_rtx (EXPR_LIST, VOIDmode, last_ptr,
        !          4908:                                  save_expr_regs);
        !          4909:     }
        !          4910: 
        !          4911:   /* After the display initializations is where the tail-recursion label
        !          4912:      should go, if we end up needing one.   Ensure we have a NOTE here
        !          4913:      since some things (like trampolines) get placed before this.  */
        !          4914:   tail_recursion_reentry = emit_note (NULL_PTR, NOTE_INSN_DELETED);
        !          4915: 
        !          4916:   /* Evaluate now the sizes of any types declared among the arguments.  */
        !          4917:   for (tem = nreverse (get_pending_sizes ()); tem; tem = TREE_CHAIN (tem))
        !          4918:     expand_expr (TREE_VALUE (tem), const0_rtx, VOIDmode, 0);
        !          4919: 
        !          4920:   /* Make sure there is a line number after the function entry setup code.  */
        !          4921:   force_next_line_note ();
        !          4922: }
        !          4923: 
        !          4924: /* Generate RTL for the end of the current function.
        !          4925:    FILENAME and LINE are the current position in the source file. 
        !          4926: 
        !          4927:    It is up to language-specific callers to do cleanups for parameters--
        !          4928:    or else, supply 1 for END_BINDINGS and we will call expand_end_bindings.  */
        !          4929: 
        !          4930: void
        !          4931: expand_function_end (filename, line, end_bindings)
        !          4932:      char *filename;
        !          4933:      int line;
        !          4934:      int end_bindings;
        !          4935: {
        !          4936:   register int i;
        !          4937:   tree link;
        !          4938: 
        !          4939:   static rtx initial_trampoline;
        !          4940: 
        !          4941:   if (output_bytecode)
        !          4942:     {
        !          4943:       bc_expand_function_end ();
        !          4944:       return;
        !          4945:     }
        !          4946: 
        !          4947: #ifdef NON_SAVING_SETJMP
        !          4948:   /* Don't put any variables in registers if we call setjmp
        !          4949:      on a machine that fails to restore the registers.  */
        !          4950:   if (NON_SAVING_SETJMP && current_function_calls_setjmp)
        !          4951:     {
        !          4952:       setjmp_protect (DECL_INITIAL (current_function_decl));
        !          4953:       setjmp_protect_args ();
        !          4954:     }
        !          4955: #endif
        !          4956: 
        !          4957:   /* Save the argument pointer if a save area was made for it.  */
        !          4958:   if (arg_pointer_save_area)
        !          4959:     {
        !          4960:       rtx x = gen_move_insn (arg_pointer_save_area, virtual_incoming_args_rtx);
        !          4961:       emit_insn_before (x, tail_recursion_reentry);
        !          4962:     }
        !          4963: 
        !          4964:   /* Initialize any trampolines required by this function.  */
        !          4965:   for (link = trampoline_list; link; link = TREE_CHAIN (link))
        !          4966:     {
        !          4967:       tree function = TREE_PURPOSE (link);
        !          4968:       rtx context = lookup_static_chain (function);
        !          4969:       rtx tramp = RTL_EXPR_RTL (TREE_VALUE (link));
        !          4970:       rtx seq;
        !          4971: 
        !          4972:       /* First make sure this compilation has a template for
        !          4973:         initializing trampolines.  */
        !          4974:       if (initial_trampoline == 0)
        !          4975:        {
        !          4976:          end_temporary_allocation ();
        !          4977:          initial_trampoline
        !          4978:            = gen_rtx (MEM, BLKmode, assemble_trampoline_template ());
        !          4979:          resume_temporary_allocation ();
        !          4980:        }
        !          4981: 
        !          4982:       /* Generate insns to initialize the trampoline.  */
        !          4983:       start_sequence ();
        !          4984:       tramp = change_address (initial_trampoline, BLKmode,
        !          4985:                              round_trampoline_addr (XEXP (tramp, 0)));
        !          4986:       emit_block_move (tramp, initial_trampoline, GEN_INT (TRAMPOLINE_SIZE),
        !          4987:                       FUNCTION_BOUNDARY / BITS_PER_UNIT);
        !          4988:       INITIALIZE_TRAMPOLINE (XEXP (tramp, 0),
        !          4989:                             XEXP (DECL_RTL (function), 0), context);
        !          4990:       seq = get_insns ();
        !          4991:       end_sequence ();
        !          4992: 
        !          4993:       /* Put those insns at entry to the containing function (this one).  */
        !          4994:       emit_insns_before (seq, tail_recursion_reentry);
        !          4995:     }
        !          4996: 
        !          4997: #if 0  /* I think unused parms are legitimate enough.  */
        !          4998:   /* Warn about unused parms.  */
        !          4999:   if (warn_unused)
        !          5000:     {
        !          5001:       rtx decl;
        !          5002: 
        !          5003:       for (decl = DECL_ARGUMENTS (current_function_decl);
        !          5004:           decl; decl = TREE_CHAIN (decl))
        !          5005:        if (! TREE_USED (decl) && TREE_CODE (decl) == VAR_DECL)
        !          5006:          warning_with_decl (decl, "unused parameter `%s'");
        !          5007:     }
        !          5008: #endif
        !          5009: 
        !          5010:   /* Delete handlers for nonlocal gotos if nothing uses them.  */
        !          5011:   if (nonlocal_goto_handler_slot != 0 && !current_function_has_nonlocal_label)
        !          5012:     delete_handlers ();
        !          5013: 
        !          5014:   /* End any sequences that failed to be closed due to syntax errors.  */
        !          5015:   while (in_sequence_p ())
        !          5016:     end_sequence ();
        !          5017: 
        !          5018:   /* Outside function body, can't compute type's actual size
        !          5019:      until next function's body starts.  */
        !          5020:   immediate_size_expand--;
        !          5021: 
        !          5022:   /* If doing stupid register allocation,
        !          5023:      mark register parms as dying here.  */
        !          5024: 
        !          5025:   if (obey_regdecls)
        !          5026:     {
        !          5027:       rtx tem;
        !          5028:       for (i = LAST_VIRTUAL_REGISTER + 1; i < max_parm_reg; i++)
        !          5029:        use_variable (regno_reg_rtx[i]);
        !          5030: 
        !          5031:       /* Likewise for the regs of all the SAVE_EXPRs in the function.  */
        !          5032: 
        !          5033:       for (tem = save_expr_regs; tem; tem = XEXP (tem, 1))
        !          5034:        {
        !          5035:          use_variable (XEXP (tem, 0));
        !          5036:          use_variable_after (XEXP (tem, 0), parm_birth_insn);
        !          5037:        }
        !          5038: 
        !          5039:       if (current_function_internal_arg_pointer != virtual_incoming_args_rtx)
        !          5040:        use_variable (current_function_internal_arg_pointer);
        !          5041:     }
        !          5042: 
        !          5043:   clear_pending_stack_adjust ();
        !          5044:   do_pending_stack_adjust ();
        !          5045: 
        !          5046:   /* Mark the end of the function body.
        !          5047:      If control reaches this insn, the function can drop through
        !          5048:      without returning a value.  */
        !          5049:   emit_note (NULL_PTR, NOTE_INSN_FUNCTION_END);
        !          5050: 
        !          5051:   /* Output a linenumber for the end of the function.
        !          5052:      SDB depends on this.  */
        !          5053:   emit_line_note_force (filename, line);
        !          5054: 
        !          5055:   /* Output the label for the actual return from the function,
        !          5056:      if one is expected.  This happens either because a function epilogue
        !          5057:      is used instead of a return instruction, or because a return was done
        !          5058:      with a goto in order to run local cleanups, or because of pcc-style
        !          5059:      structure returning.  */
        !          5060: 
        !          5061:   if (return_label)
        !          5062:     emit_label (return_label);
        !          5063: 
        !          5064:   /* C++ uses this.  */
        !          5065:   if (end_bindings)
        !          5066:     expand_end_bindings (0, 0, 0);
        !          5067: 
        !          5068:   /* If we had calls to alloca, and this machine needs
        !          5069:      an accurate stack pointer to exit the function,
        !          5070:      insert some code to save and restore the stack pointer.  */
        !          5071: #ifdef EXIT_IGNORE_STACK
        !          5072:   if (! EXIT_IGNORE_STACK)
        !          5073: #endif
        !          5074:     if (current_function_calls_alloca)
        !          5075:       {
        !          5076:        rtx tem = 0;
        !          5077: 
        !          5078:        emit_stack_save (SAVE_FUNCTION, &tem, parm_birth_insn);
        !          5079:        emit_stack_restore (SAVE_FUNCTION, tem, NULL_RTX);
        !          5080:       }
        !          5081: 
        !          5082:   /* If scalar return value was computed in a pseudo-reg,
        !          5083:      copy that to the hard return register.  */
        !          5084:   if (DECL_RTL (DECL_RESULT (current_function_decl)) != 0
        !          5085:       && GET_CODE (DECL_RTL (DECL_RESULT (current_function_decl))) == REG
        !          5086:       && (REGNO (DECL_RTL (DECL_RESULT (current_function_decl)))
        !          5087:          >= FIRST_PSEUDO_REGISTER))
        !          5088:     {
        !          5089:       rtx real_decl_result;
        !          5090: 
        !          5091: #ifdef FUNCTION_OUTGOING_VALUE
        !          5092:       real_decl_result
        !          5093:        = FUNCTION_OUTGOING_VALUE (TREE_TYPE (DECL_RESULT (current_function_decl)),
        !          5094:                                   current_function_decl);
        !          5095: #else
        !          5096:       real_decl_result
        !          5097:        = FUNCTION_VALUE (TREE_TYPE (DECL_RESULT (current_function_decl)),
        !          5098:                          current_function_decl);
        !          5099: #endif
        !          5100:       REG_FUNCTION_VALUE_P (real_decl_result) = 1;
        !          5101:       emit_move_insn (real_decl_result,
        !          5102:                      DECL_RTL (DECL_RESULT (current_function_decl)));
        !          5103:       emit_insn (gen_rtx (USE, VOIDmode, real_decl_result));
        !          5104:     }
        !          5105: 
        !          5106:   /* If returning a structure, arrange to return the address of the value
        !          5107:      in a place where debuggers expect to find it.
        !          5108: 
        !          5109:      If returning a structure PCC style,
        !          5110:      the caller also depends on this value.
        !          5111:      And current_function_returns_pcc_struct is not necessarily set.  */
        !          5112:   if (current_function_returns_struct
        !          5113:       || current_function_returns_pcc_struct)
        !          5114:     {
        !          5115:       rtx value_address = XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0);
        !          5116:       tree type = TREE_TYPE (DECL_RESULT (current_function_decl));
        !          5117: #ifdef FUNCTION_OUTGOING_VALUE
        !          5118:       rtx outgoing
        !          5119:        = FUNCTION_OUTGOING_VALUE (build_pointer_type (type),
        !          5120:                                   current_function_decl);
        !          5121: #else
        !          5122:       rtx outgoing
        !          5123:        = FUNCTION_VALUE (build_pointer_type (type),
        !          5124:                          current_function_decl);
        !          5125: #endif
        !          5126: 
        !          5127:       /* Mark this as a function return value so integrate will delete the
        !          5128:         assignment and USE below when inlining this function.  */
        !          5129:       REG_FUNCTION_VALUE_P (outgoing) = 1;
        !          5130: 
        !          5131:       emit_move_insn (outgoing, value_address);
        !          5132:       use_variable (outgoing);
        !          5133:     }
        !          5134: 
        !          5135:   /* Output a return insn if we are using one.
        !          5136:      Otherwise, let the rtl chain end here, to drop through
        !          5137:      into the epilogue.  */
        !          5138: 
        !          5139: #ifdef HAVE_return
        !          5140:   if (HAVE_return)
        !          5141:     {
        !          5142:       emit_jump_insn (gen_return ());
        !          5143:       emit_barrier ();
        !          5144:     }
        !          5145: #endif
        !          5146: 
        !          5147:   /* Fix up any gotos that jumped out to the outermost
        !          5148:      binding level of the function.
        !          5149:      Must follow emitting RETURN_LABEL.  */
        !          5150: 
        !          5151:   /* If you have any cleanups to do at this point,
        !          5152:      and they need to create temporary variables,
        !          5153:      then you will lose.  */
        !          5154:   fixup_gotos (NULL_PTR, NULL_RTX, NULL_TREE, get_insns (), 0);
        !          5155: }
        !          5156: 
        !          5157: /* These arrays record the INSN_UIDs of the prologue and epilogue insns.  */
        !          5158: 
        !          5159: static int *prologue;
        !          5160: static int *epilogue;
        !          5161: 
        !          5162: /* Create an array that records the INSN_UIDs of INSNS (either a sequence
        !          5163:    or a single insn).  */
        !          5164: 
        !          5165: static int *
        !          5166: record_insns (insns)
        !          5167:      rtx insns;
        !          5168: {
        !          5169:   int *vec;
        !          5170: 
        !          5171:   if (GET_CODE (insns) == SEQUENCE)
        !          5172:     {
        !          5173:       int len = XVECLEN (insns, 0);
        !          5174:       vec = (int *) oballoc ((len + 1) * sizeof (int));
        !          5175:       vec[len] = 0;
        !          5176:       while (--len >= 0)
        !          5177:        vec[len] = INSN_UID (XVECEXP (insns, 0, len));
        !          5178:     }
        !          5179:   else
        !          5180:     {
        !          5181:       vec = (int *) oballoc (2 * sizeof (int));
        !          5182:       vec[0] = INSN_UID (insns);
        !          5183:       vec[1] = 0;
        !          5184:     }
        !          5185:   return vec;
        !          5186: }
        !          5187: 
        !          5188: /* Determine how many INSN_UIDs in VEC are part of INSN.  */
        !          5189: 
        !          5190: static int
        !          5191: contains (insn, vec)
        !          5192:      rtx insn;
        !          5193:      int *vec;
        !          5194: {
        !          5195:   register int i, j;
        !          5196: 
        !          5197:   if (GET_CODE (insn) == INSN
        !          5198:       && GET_CODE (PATTERN (insn)) == SEQUENCE)
        !          5199:     {
        !          5200:       int count = 0;
        !          5201:       for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
        !          5202:        for (j = 0; vec[j]; j++)
        !          5203:          if (INSN_UID (XVECEXP (PATTERN (insn), 0, i)) == vec[j])
        !          5204:            count++;
        !          5205:       return count;
        !          5206:     }
        !          5207:   else
        !          5208:     {
        !          5209:       for (j = 0; vec[j]; j++)
        !          5210:        if (INSN_UID (insn) == vec[j])
        !          5211:          return 1;
        !          5212:     }
        !          5213:   return 0;
        !          5214: }
        !          5215: 
        !          5216: /* Generate the prologe and epilogue RTL if the machine supports it.  Thread
        !          5217:    this into place with notes indicating where the prologue ends and where
        !          5218:    the epilogue begins.  Update the basic block information when possible.  */
        !          5219: 
        !          5220: void
        !          5221: thread_prologue_and_epilogue_insns (f)
        !          5222:      rtx f;
        !          5223: {
        !          5224: #ifdef HAVE_prologue
        !          5225:   if (HAVE_prologue)
        !          5226:     {
        !          5227:       rtx head, seq, insn;
        !          5228: 
        !          5229:       /* The first insn (a NOTE_INSN_DELETED) is followed by zero or more
        !          5230:         prologue insns and a NOTE_INSN_PROLOGUE_END.  */
        !          5231:       emit_note_after (NOTE_INSN_PROLOGUE_END, f);
        !          5232:       seq = gen_prologue ();
        !          5233:       head = emit_insn_after (seq, f);
        !          5234: 
        !          5235:       /* Include the new prologue insns in the first block.  Ignore them
        !          5236:         if they form a basic block unto themselves.  */
        !          5237:       if (basic_block_head && n_basic_blocks
        !          5238: #ifdef NEXT_SEMANTICS
        !          5239:          && !obey_regdecls 
        !          5240: #endif 
        !          5241:          && GET_CODE (basic_block_head[0]) != CODE_LABEL)
        !          5242:        basic_block_head[0] = NEXT_INSN (f);
        !          5243: 
        !          5244:       /* Retain a map of the prologue insns.  */
        !          5245:       prologue = record_insns (GET_CODE (seq) == SEQUENCE ? seq : head);
        !          5246:     }
        !          5247:   else
        !          5248: #endif
        !          5249:     prologue = 0;
        !          5250: 
        !          5251: #ifdef HAVE_epilogue
        !          5252:   if (HAVE_epilogue)
        !          5253:     {
        !          5254:       rtx insn = get_last_insn ();
        !          5255:       rtx prev = prev_nonnote_insn (insn);
        !          5256: 
        !          5257:       /* If we end with a BARRIER, we don't need an epilogue.  */
        !          5258:       if (! (prev && GET_CODE (prev) == BARRIER))
        !          5259:        {
        !          5260:          rtx tail, seq, tem;
        !          5261:          rtx first_use = 0;
        !          5262:          rtx last_use = 0;
        !          5263: 
        !          5264:          /* The last basic block ends with a NOTE_INSN_EPILOGUE_BEG, the
        !          5265:             epilogue insns, the USE insns at the end of a function,
        !          5266:             the jump insn that returns, and then a BARRIER.  */
        !          5267: 
        !          5268:          /* Move the USE insns at the end of a function onto a list.  */
        !          5269:          while (prev
        !          5270:                 && GET_CODE (prev) == INSN
        !          5271:                 && GET_CODE (PATTERN (prev)) == USE)
        !          5272:            {
        !          5273:              tem = prev;
        !          5274:              prev = prev_nonnote_insn (prev);
        !          5275: 
        !          5276:              NEXT_INSN (PREV_INSN (tem)) = NEXT_INSN (tem);
        !          5277:              PREV_INSN (NEXT_INSN (tem)) = PREV_INSN (tem);
        !          5278:              if (first_use)
        !          5279:                {
        !          5280:                  NEXT_INSN (tem) = first_use;
        !          5281:                  PREV_INSN (first_use) = tem;
        !          5282:                }
        !          5283:              first_use = tem;
        !          5284:              if (!last_use)
        !          5285:                last_use = tem;
        !          5286:            }
        !          5287: 
        !          5288:          emit_barrier_after (insn);
        !          5289: 
        !          5290:          seq = gen_epilogue ();
        !          5291:          tail = emit_jump_insn_after (seq, insn);
        !          5292: 
        !          5293:          /* Insert the USE insns immediately before the return insn, which
        !          5294:             must be the first instruction before the final barrier.  */
        !          5295:          if (first_use)
        !          5296:            {
        !          5297:              tem = prev_nonnote_insn (get_last_insn ());
        !          5298:              NEXT_INSN (PREV_INSN (tem)) = first_use;
        !          5299:              PREV_INSN (first_use) = PREV_INSN (tem);
        !          5300:              PREV_INSN (tem) = last_use;
        !          5301:              NEXT_INSN (last_use) = tem;
        !          5302:            }
        !          5303: 
        !          5304:          emit_note_after (NOTE_INSN_EPILOGUE_BEG, insn);
        !          5305: 
        !          5306:          /* Include the new epilogue insns in the last block.  Ignore
        !          5307:             them if they form a basic block unto themselves.  */
        !          5308:          if (basic_block_end && n_basic_blocks
        !          5309: #ifdef NEXT_SEMANTICS
        !          5310:              && !obey_regdecls
        !          5311: #endif
        !          5312:              && GET_CODE (basic_block_end[n_basic_blocks - 1]) != JUMP_INSN)
        !          5313:            basic_block_end[n_basic_blocks - 1] = tail;
        !          5314: 
        !          5315:          /* Retain a map of the epilogue insns.  */
        !          5316:          epilogue = record_insns (GET_CODE (seq) == SEQUENCE ? seq : tail);
        !          5317:          return;
        !          5318:        }
        !          5319:     }
        !          5320: #endif
        !          5321:   epilogue = 0;
        !          5322: }
        !          5323: 
        !          5324: /* Reposition the prologue-end and epilogue-begin notes after instruction
        !          5325:    scheduling and delayed branch scheduling.  */
        !          5326: 
        !          5327: void
        !          5328: reposition_prologue_and_epilogue_notes (f)
        !          5329:      rtx f;
        !          5330: {
        !          5331: #if defined (HAVE_prologue) || defined (HAVE_epilogue)
        !          5332:   /* Reposition the prologue and epilogue notes.  */
        !          5333:   if (n_basic_blocks)
        !          5334:     {
        !          5335:       rtx next, prev;
        !          5336:       int len;
        !          5337: 
        !          5338:       if (prologue)
        !          5339:        {
        !          5340:          register rtx insn, note = 0;
        !          5341: 
        !          5342:          /* Scan from the beginning until we reach the last prologue insn.
        !          5343:             We apparently can't depend on basic_block_{head,end} after
        !          5344:             reorg has run.  */
        !          5345:          for (len = 0; prologue[len]; len++)
        !          5346:            ;
        !          5347:          for (insn = f; len && insn; insn = NEXT_INSN (insn))
        !          5348:            {
        !          5349:              if (GET_CODE (insn) == NOTE)
        !          5350:                {
        !          5351:                  if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_PROLOGUE_END)
        !          5352:                    note = insn;
        !          5353:                }
        !          5354:              else if ((len -= contains (insn, prologue)) == 0)
        !          5355:                {
        !          5356:                  /* Find the prologue-end note if we haven't already, and
        !          5357:                     move it to just after the last prologue insn.  */
        !          5358:                  if (note == 0)
        !          5359:                    {
        !          5360:                      for (note = insn; note = NEXT_INSN (note);)
        !          5361:                        if (GET_CODE (note) == NOTE
        !          5362:                            && NOTE_LINE_NUMBER (note) == NOTE_INSN_PROLOGUE_END)
        !          5363:                          break;
        !          5364:                    }
        !          5365:                  next = NEXT_INSN (note);
        !          5366:                  prev = PREV_INSN (note);
        !          5367:                  if (prev)
        !          5368:                    NEXT_INSN (prev) = next;
        !          5369:                  if (next)
        !          5370:                    PREV_INSN (next) = prev;
        !          5371:                  add_insn_after (note, insn);
        !          5372:                }
        !          5373:            }
        !          5374:        }
        !          5375: 
        !          5376:       if (epilogue)
        !          5377:        {
        !          5378:          register rtx insn, note = 0;
        !          5379: 
        !          5380:          /* Scan from the end until we reach the first epilogue insn.
        !          5381:             We apparently can't depend on basic_block_{head,end} after
        !          5382:             reorg has run.  */
        !          5383:          for (len = 0; epilogue[len]; len++)
        !          5384:            ;
        !          5385:          for (insn = get_last_insn (); len && insn; insn = PREV_INSN (insn))
        !          5386:            {
        !          5387:              if (GET_CODE (insn) == NOTE)
        !          5388:                {
        !          5389:                  if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EPILOGUE_BEG)
        !          5390:                    note = insn;
        !          5391:                }
        !          5392:              else if ((len -= contains (insn, epilogue)) == 0)
        !          5393:                {
        !          5394:                  /* Find the epilogue-begin note if we haven't already, and
        !          5395:                     move it to just before the first epilogue insn.  */
        !          5396:                  if (note == 0)
        !          5397:                    {
        !          5398:                      for (note = insn; note = PREV_INSN (note);)
        !          5399:                        if (GET_CODE (note) == NOTE
        !          5400:                            && NOTE_LINE_NUMBER (note) == NOTE_INSN_EPILOGUE_BEG)
        !          5401:                          break;
        !          5402:                    }
        !          5403:                  next = NEXT_INSN (note);
        !          5404:                  prev = PREV_INSN (note);
        !          5405:                  if (prev)
        !          5406:                    NEXT_INSN (prev) = next;
        !          5407:                  if (next)
        !          5408:                    PREV_INSN (next) = prev;
        !          5409:                  add_insn_after (note, PREV_INSN (insn));
        !          5410:                }
        !          5411:            }
        !          5412:        }
        !          5413:     }
        !          5414: #endif /* HAVE_prologue or HAVE_epilogue */
        !          5415: }

unix.superglobalmegacorp.com

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