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

1.1     ! root        1: /* Convert tree expression to rtl instructions, for GNU compiler.
        !             2:    Copyright (C) 1988, 1992, 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: #include "config.h"
        !            22: #include "machmode.h"
        !            23: #include "rtl.h"
        !            24: #include "tree.h"
        !            25: #include "obstack.h"
        !            26: #include "flags.h"
        !            27: #include "function.h"
        !            28: #include "insn-flags.h"
        !            29: #include "insn-codes.h"
        !            30: #include "expr.h"
        !            31: #include "insn-config.h"
        !            32: #include "recog.h"
        !            33: #include "output.h"
        !            34: #include "typeclass.h"
        !            35: 
        !            36: #include "bytecode.h"
        !            37: #include "bc-opcode.h"
        !            38: #include "bc-typecd.h"
        !            39: #include "bc-optab.h"
        !            40: #include "bc-emit.h"
        !            41: 
        !            42: 
        !            43: #define CEIL(x,y) (((x) + (y) - 1) / (y))
        !            44: 
        !            45: /* Decide whether a function's arguments should be processed
        !            46:    from first to last or from last to first.
        !            47: 
        !            48:    They should if the stack and args grow in opposite directions, but
        !            49:    only if we have push insns.  */
        !            50: 
        !            51: #ifdef PUSH_ROUNDING
        !            52: 
        !            53: #if defined (STACK_GROWS_DOWNWARD) != defined (ARGS_GROW_DOWNWARD)
        !            54: #define PUSH_ARGS_REVERSED     /* If it's last to first */
        !            55: #endif
        !            56: 
        !            57: #endif
        !            58: 
        !            59: #ifndef STACK_PUSH_CODE
        !            60: #ifdef STACK_GROWS_DOWNWARD
        !            61: #define STACK_PUSH_CODE PRE_DEC
        !            62: #else
        !            63: #define STACK_PUSH_CODE PRE_INC
        !            64: #endif
        !            65: #endif
        !            66: 
        !            67: /* Like STACK_BOUNDARY but in units of bytes, not bits.  */
        !            68: #define STACK_BYTES (STACK_BOUNDARY / BITS_PER_UNIT)
        !            69: 
        !            70: /* If this is nonzero, we do not bother generating VOLATILE
        !            71:    around volatile memory references, and we are willing to
        !            72:    output indirect addresses.  If cse is to follow, we reject
        !            73:    indirect addresses so a useful potential cse is generated;
        !            74:    if it is used only once, instruction combination will produce
        !            75:    the same indirect address eventually.  */
        !            76: int cse_not_expected;
        !            77: 
        !            78: /* Nonzero to generate code for all the subroutines within an
        !            79:    expression before generating the upper levels of the expression.
        !            80:    Nowadays this is never zero.  */
        !            81: int do_preexpand_calls = 1;
        !            82: 
        !            83: /* Number of units that we should eventually pop off the stack.
        !            84:    These are the arguments to function calls that have already returned.  */
        !            85: int pending_stack_adjust;
        !            86: 
        !            87: /* Nonzero means stack pops must not be deferred, and deferred stack
        !            88:    pops must not be output.  It is nonzero inside a function call,
        !            89:    inside a conditional expression, inside a statement expression,
        !            90:    and in other cases as well.  */
        !            91: int inhibit_defer_pop;
        !            92: 
        !            93: /* A list of all cleanups which belong to the arguments of
        !            94:    function calls being expanded by expand_call.  */
        !            95: tree cleanups_this_call;
        !            96: 
        !            97: /* Nonzero means __builtin_saveregs has already been done in this function.
        !            98:    The value is the pseudoreg containing the value __builtin_saveregs
        !            99:    returned.  */
        !           100: static rtx saveregs_value;
        !           101: 
        !           102: /* Similarly for __builtin_apply_args.  */
        !           103: static rtx apply_args_value;
        !           104: 
        !           105: /* This structure is used by move_by_pieces to describe the move to
        !           106:    be performed.  */
        !           107: 
        !           108: struct move_by_pieces
        !           109: {
        !           110:   rtx to;
        !           111:   rtx to_addr;
        !           112:   int autinc_to;
        !           113:   int explicit_inc_to;
        !           114:   rtx from;
        !           115:   rtx from_addr;
        !           116:   int autinc_from;
        !           117:   int explicit_inc_from;
        !           118:   int len;
        !           119:   int offset;
        !           120:   int reverse;
        !           121: };
        !           122: 
        !           123: /* Used to generate bytecodes: keep track of size of local variables,
        !           124:    as well as depth of arithmetic stack. (Notice that variables are
        !           125:    stored on the machine's stack, not the arithmetic stack.) */
        !           126: 
        !           127: int local_vars_size;
        !           128: extern int stack_depth;
        !           129: extern int max_stack_depth;
        !           130: extern struct obstack permanent_obstack;
        !           131: 
        !           132: 
        !           133: static rtx enqueue_insn                PROTO((rtx, rtx));
        !           134: static int queued_subexp_p     PROTO((rtx));
        !           135: static void init_queue         PROTO((void));
        !           136: static void move_by_pieces     PROTO((rtx, rtx, int, int));
        !           137: static int move_by_pieces_ninsns PROTO((unsigned int, int));
        !           138: static void move_by_pieces_1   PROTO((rtx (*) (), enum machine_mode,
        !           139:                                       struct move_by_pieces *));
        !           140: static void group_insns                PROTO((rtx));
        !           141: static void store_constructor  PROTO((tree, rtx));
        !           142: static rtx store_field         PROTO((rtx, int, int, enum machine_mode, tree,
        !           143:                                       enum machine_mode, int, int, int));
        !           144: static tree save_noncopied_parts PROTO((tree, tree));
        !           145: static tree init_noncopied_parts PROTO((tree, tree));
        !           146: static int safe_from_p         PROTO((rtx, tree));
        !           147: static int fixed_type_p                PROTO((tree));
        !           148: static int get_pointer_alignment PROTO((tree, unsigned));
        !           149: static tree string_constant    PROTO((tree, tree *));
        !           150: static tree c_strlen           PROTO((tree));
        !           151: static rtx expand_builtin  PROTO((tree, rtx, rtx, enum machine_mode, int));
        !           152: static int apply_args_size     PROTO((void));
        !           153: static int apply_result_size   PROTO((void));
        !           154: static rtx result_vector       PROTO((int, rtx));
        !           155: static rtx expand_builtin_apply_args PROTO((void));
        !           156: static rtx expand_builtin_apply        PROTO((rtx, rtx, rtx));
        !           157: static void expand_builtin_return PROTO((rtx));
        !           158: static rtx expand_increment    PROTO((tree, int));
        !           159: rtx bc_expand_increment                PROTO((struct increment_operator *, tree));
        !           160: tree bc_runtime_type_code      PROTO((tree));
        !           161: rtx bc_allocate_local          PROTO((int, int));
        !           162: void bc_store_memory           PROTO((tree, tree));
        !           163: tree bc_expand_component_address PROTO((tree));
        !           164: tree bc_expand_address                 PROTO((tree));
        !           165: void bc_expand_constructor     PROTO((tree));
        !           166: void bc_adjust_stack           PROTO((int));
        !           167: tree bc_canonicalize_array_ref PROTO((tree));
        !           168: void bc_load_memory            PROTO((tree, tree));
        !           169: void bc_load_externaddr                PROTO((rtx));
        !           170: void bc_load_externaddr_id     PROTO((tree, int));
        !           171: void bc_load_localaddr         PROTO((rtx));
        !           172: void bc_load_parmaddr          PROTO((rtx));
        !           173: static void preexpand_calls    PROTO((tree));
        !           174: static void do_jump_by_parts_greater PROTO((tree, int, rtx, rtx));
        !           175: static void do_jump_by_parts_greater_rtx PROTO((enum machine_mode, int, rtx, rtx, rtx, rtx));
        !           176: static void do_jump_by_parts_equality PROTO((tree, rtx, rtx));
        !           177: static void do_jump_by_parts_equality_rtx PROTO((rtx, rtx, rtx));
        !           178: static void do_jump_for_compare        PROTO((rtx, rtx, rtx));
        !           179: static rtx compare             PROTO((tree, enum rtx_code, enum rtx_code));
        !           180: static rtx do_store_flag       PROTO((tree, rtx, enum machine_mode, int));
        !           181: 
        !           182: /* Record for each mode whether we can move a register directly to or
        !           183:    from an object of that mode in memory.  If we can't, we won't try
        !           184:    to use that mode directly when accessing a field of that mode.  */
        !           185: 
        !           186: static char direct_load[NUM_MACHINE_MODES];
        !           187: static char direct_store[NUM_MACHINE_MODES];
        !           188: 
        !           189: /* MOVE_RATIO is the number of move instructions that is better than
        !           190:    a block move.  */
        !           191: 
        !           192: #ifndef MOVE_RATIO
        !           193: #if defined (HAVE_movstrqi) || defined (HAVE_movstrhi) || defined (HAVE_movstrsi) || defined (HAVE_movstrdi) || defined (HAVE_movstrti)
        !           194: #define MOVE_RATIO 2
        !           195: #else
        !           196: /* A value of around 6 would minimize code size; infinity would minimize
        !           197:    execution time.  */
        !           198: #define MOVE_RATIO 15
        !           199: #endif
        !           200: #endif
        !           201: 
        !           202: /* This array records the insn_code of insns to perform block moves.  */
        !           203: enum insn_code movstr_optab[NUM_MACHINE_MODES];
        !           204: 
        !           205: /* SLOW_UNALIGNED_ACCESS is non-zero if unaligned accesses are very slow. */
        !           206: 
        !           207: #ifndef SLOW_UNALIGNED_ACCESS
        !           208: #define SLOW_UNALIGNED_ACCESS 0
        !           209: #endif
        !           210: 
        !           211: /* Register mappings for target machines without register windows.  */
        !           212: #ifndef INCOMING_REGNO
        !           213: #define INCOMING_REGNO(OUT) (OUT)
        !           214: #endif
        !           215: #ifndef OUTGOING_REGNO
        !           216: #define OUTGOING_REGNO(IN) (IN)
        !           217: #endif
        !           218: 
        !           219: /* Maps used to convert modes to const, load, and store bytecodes. */
        !           220: enum bytecode_opcode mode_to_const_map[MAX_MACHINE_MODE];
        !           221: enum bytecode_opcode mode_to_load_map[MAX_MACHINE_MODE];
        !           222: enum bytecode_opcode mode_to_store_map[MAX_MACHINE_MODE];
        !           223: 
        !           224: /* Initialize maps used to convert modes to const, load, and store
        !           225:    bytecodes. */
        !           226: void
        !           227: bc_init_mode_to_opcode_maps ()
        !           228: {
        !           229:   int mode;
        !           230: 
        !           231:   for (mode = 0; mode < (int) MAX_MACHINE_MODE; mode++)
        !           232:     mode_to_const_map[mode] =
        !           233:       mode_to_load_map[mode] =
        !           234:        mode_to_store_map[mode] = neverneverland;
        !           235:       
        !           236: #define DEF_MODEMAP(SYM, CODE, UCODE, CONST, LOAD, STORE) \
        !           237:   mode_to_const_map[(int) SYM] = CONST; \
        !           238:   mode_to_load_map[(int) SYM] = LOAD; \
        !           239:   mode_to_store_map[(int) SYM] = STORE;
        !           240: 
        !           241: #include "modemap.def"
        !           242: #undef DEF_MODEMAP
        !           243: }
        !           244: 
        !           245: /* This is run once per compilation to set up which modes can be used
        !           246:    directly in memory and to initialize the block move optab.  */
        !           247: 
        !           248: void
        !           249: init_expr_once ()
        !           250: {
        !           251:   rtx insn, pat;
        !           252:   enum machine_mode mode;
        !           253:   /* Try indexing by frame ptr and try by stack ptr.
        !           254:      It is known that on the Convex the stack ptr isn't a valid index.
        !           255:      With luck, one or the other is valid on any machine.  */
        !           256:   rtx mem = gen_rtx (MEM, VOIDmode, stack_pointer_rtx);
        !           257:   rtx mem1 = gen_rtx (MEM, VOIDmode, frame_pointer_rtx);
        !           258: 
        !           259:   start_sequence ();
        !           260:   insn = emit_insn (gen_rtx (SET, 0, 0));
        !           261:   pat = PATTERN (insn);
        !           262: 
        !           263:   for (mode = VOIDmode; (int) mode < NUM_MACHINE_MODES;
        !           264:        mode = (enum machine_mode) ((int) mode + 1))
        !           265:     {
        !           266:       int regno;
        !           267:       rtx reg;
        !           268:       int num_clobbers;
        !           269: 
        !           270:       direct_load[(int) mode] = direct_store[(int) mode] = 0;
        !           271:       PUT_MODE (mem, mode);
        !           272:       PUT_MODE (mem1, mode);
        !           273: 
        !           274:       /* See if there is some register that can be used in this mode and
        !           275:         directly loaded or stored from memory.  */
        !           276: 
        !           277:       if (mode != VOIDmode && mode != BLKmode)
        !           278:        for (regno = 0; regno < FIRST_PSEUDO_REGISTER
        !           279:             && (direct_load[(int) mode] == 0 || direct_store[(int) mode] == 0);
        !           280:             regno++)
        !           281:          {
        !           282:            if (! HARD_REGNO_MODE_OK (regno, mode))
        !           283:              continue;
        !           284: 
        !           285:            reg = gen_rtx (REG, mode, regno);
        !           286: 
        !           287:            SET_SRC (pat) = mem;
        !           288:            SET_DEST (pat) = reg;
        !           289:            if (recog (pat, insn, &num_clobbers) >= 0)
        !           290:              direct_load[(int) mode] = 1;
        !           291: 
        !           292:            SET_SRC (pat) = mem1;
        !           293:            SET_DEST (pat) = reg;
        !           294:            if (recog (pat, insn, &num_clobbers) >= 0)
        !           295:              direct_load[(int) mode] = 1;
        !           296: 
        !           297:            SET_SRC (pat) = reg;
        !           298:            SET_DEST (pat) = mem;
        !           299:            if (recog (pat, insn, &num_clobbers) >= 0)
        !           300:              direct_store[(int) mode] = 1;
        !           301: 
        !           302:            SET_SRC (pat) = reg;
        !           303:            SET_DEST (pat) = mem1;
        !           304:            if (recog (pat, insn, &num_clobbers) >= 0)
        !           305:              direct_store[(int) mode] = 1;
        !           306:          }
        !           307:     }
        !           308: 
        !           309:   end_sequence ();
        !           310: }
        !           311:       
        !           312: /* This is run at the start of compiling a function.  */
        !           313: 
        !           314: void
        !           315: init_expr ()
        !           316: {
        !           317:   init_queue ();
        !           318: 
        !           319:   pending_stack_adjust = 0;
        !           320:   inhibit_defer_pop = 0;
        !           321:   cleanups_this_call = 0;
        !           322:   saveregs_value = 0;
        !           323:   apply_args_value = 0;
        !           324:   forced_labels = 0;
        !           325: }
        !           326: 
        !           327: /* Save all variables describing the current status into the structure *P.
        !           328:    This is used before starting a nested function.  */
        !           329: 
        !           330: void
        !           331: save_expr_status (p)
        !           332:      struct function *p;
        !           333: {
        !           334:   /* Instead of saving the postincrement queue, empty it.  */
        !           335:   emit_queue ();
        !           336: 
        !           337:   p->pending_stack_adjust = pending_stack_adjust;
        !           338:   p->inhibit_defer_pop = inhibit_defer_pop;
        !           339:   p->cleanups_this_call = cleanups_this_call;
        !           340:   p->saveregs_value = saveregs_value;
        !           341:   p->apply_args_value = apply_args_value;
        !           342:   p->forced_labels = forced_labels;
        !           343: 
        !           344:   pending_stack_adjust = 0;
        !           345:   inhibit_defer_pop = 0;
        !           346:   cleanups_this_call = 0;
        !           347:   saveregs_value = 0;
        !           348:   apply_args_value = 0;
        !           349:   forced_labels = 0;
        !           350: }
        !           351: 
        !           352: /* Restore all variables describing the current status from the structure *P.
        !           353:    This is used after a nested function.  */
        !           354: 
        !           355: void
        !           356: restore_expr_status (p)
        !           357:      struct function *p;
        !           358: {
        !           359:   pending_stack_adjust = p->pending_stack_adjust;
        !           360:   inhibit_defer_pop = p->inhibit_defer_pop;
        !           361:   cleanups_this_call = p->cleanups_this_call;
        !           362:   saveregs_value = p->saveregs_value;
        !           363:   apply_args_value = p->apply_args_value;
        !           364:   forced_labels = p->forced_labels;
        !           365: }
        !           366: 
        !           367: /* Manage the queue of increment instructions to be output
        !           368:    for POSTINCREMENT_EXPR expressions, etc.  */
        !           369: 
        !           370: static rtx pending_chain;
        !           371: 
        !           372: /* Queue up to increment (or change) VAR later.  BODY says how:
        !           373:    BODY should be the same thing you would pass to emit_insn
        !           374:    to increment right away.  It will go to emit_insn later on.
        !           375: 
        !           376:    The value is a QUEUED expression to be used in place of VAR
        !           377:    where you want to guarantee the pre-incrementation value of VAR.  */
        !           378: 
        !           379: static rtx
        !           380: enqueue_insn (var, body)
        !           381:      rtx var, body;
        !           382: {
        !           383:   pending_chain = gen_rtx (QUEUED, GET_MODE (var),
        !           384:                           var, NULL_RTX, NULL_RTX, body, pending_chain);
        !           385:   return pending_chain;
        !           386: }
        !           387: 
        !           388: /* Use protect_from_queue to convert a QUEUED expression
        !           389:    into something that you can put immediately into an instruction.
        !           390:    If the queued incrementation has not happened yet,
        !           391:    protect_from_queue returns the variable itself.
        !           392:    If the incrementation has happened, protect_from_queue returns a temp
        !           393:    that contains a copy of the old value of the variable.
        !           394: 
        !           395:    Any time an rtx which might possibly be a QUEUED is to be put
        !           396:    into an instruction, it must be passed through protect_from_queue first.
        !           397:    QUEUED expressions are not meaningful in instructions.
        !           398: 
        !           399:    Do not pass a value through protect_from_queue and then hold
        !           400:    on to it for a while before putting it in an instruction!
        !           401:    If the queue is flushed in between, incorrect code will result.  */
        !           402: 
        !           403: rtx
        !           404: protect_from_queue (x, modify)
        !           405:      register rtx x;
        !           406:      int modify;
        !           407: {
        !           408:   register RTX_CODE code = GET_CODE (x);
        !           409: 
        !           410: #if 0  /* A QUEUED can hang around after the queue is forced out.  */
        !           411:   /* Shortcut for most common case.  */
        !           412:   if (pending_chain == 0)
        !           413:     return x;
        !           414: #endif
        !           415: 
        !           416:   if (code != QUEUED)
        !           417:     {
        !           418:       /* A special hack for read access to (MEM (QUEUED ...))
        !           419:         to facilitate use of autoincrement.
        !           420:         Make a copy of the contents of the memory location
        !           421:         rather than a copy of the address, but not
        !           422:         if the value is of mode BLKmode.  */
        !           423:       if (code == MEM && GET_MODE (x) != BLKmode
        !           424:          && GET_CODE (XEXP (x, 0)) == QUEUED && !modify)
        !           425:        {
        !           426:          register rtx y = XEXP (x, 0);
        !           427:          XEXP (x, 0) = QUEUED_VAR (y);
        !           428:          if (QUEUED_INSN (y))
        !           429:            {
        !           430:              register rtx temp = gen_reg_rtx (GET_MODE (x));
        !           431:              emit_insn_before (gen_move_insn (temp, x),
        !           432:                                QUEUED_INSN (y));
        !           433:              return temp;
        !           434:            }
        !           435:          return x;
        !           436:        }
        !           437:       /* Otherwise, recursively protect the subexpressions of all
        !           438:         the kinds of rtx's that can contain a QUEUED.  */
        !           439:       if (code == MEM)
        !           440:        {
        !           441:          rtx tem = protect_from_queue (XEXP (x, 0), 0);
        !           442:          if (tem != XEXP (x, 0))
        !           443:            {
        !           444:              x = copy_rtx (x);
        !           445:              XEXP (x, 0) = tem;
        !           446:            }
        !           447:        }
        !           448:       else if (code == PLUS || code == MULT)
        !           449:        {
        !           450:          rtx new0 = protect_from_queue (XEXP (x, 0), 0);
        !           451:          rtx new1 = protect_from_queue (XEXP (x, 1), 0);
        !           452:          if (new0 != XEXP (x, 0) || new1 != XEXP (x, 1))
        !           453:            {
        !           454:              x = copy_rtx (x);
        !           455:              XEXP (x, 0) = new0;
        !           456:              XEXP (x, 1) = new1;
        !           457:            }
        !           458:        }
        !           459:       return x;
        !           460:     }
        !           461:   /* If the increment has not happened, use the variable itself.  */
        !           462:   if (QUEUED_INSN (x) == 0)
        !           463:     return QUEUED_VAR (x);
        !           464:   /* If the increment has happened and a pre-increment copy exists,
        !           465:      use that copy.  */
        !           466:   if (QUEUED_COPY (x) != 0)
        !           467:     return QUEUED_COPY (x);
        !           468:   /* The increment has happened but we haven't set up a pre-increment copy.
        !           469:      Set one up now, and use it.  */
        !           470:   QUEUED_COPY (x) = gen_reg_rtx (GET_MODE (QUEUED_VAR (x)));
        !           471:   emit_insn_before (gen_move_insn (QUEUED_COPY (x), QUEUED_VAR (x)),
        !           472:                    QUEUED_INSN (x));
        !           473:   return QUEUED_COPY (x);
        !           474: }
        !           475: 
        !           476: /* Return nonzero if X contains a QUEUED expression:
        !           477:    if it contains anything that will be altered by a queued increment.
        !           478:    We handle only combinations of MEM, PLUS, MINUS and MULT operators
        !           479:    since memory addresses generally contain only those.  */
        !           480: 
        !           481: static int
        !           482: queued_subexp_p (x)
        !           483:      rtx x;
        !           484: {
        !           485:   register enum rtx_code code = GET_CODE (x);
        !           486:   switch (code)
        !           487:     {
        !           488:     case QUEUED:
        !           489:       return 1;
        !           490:     case MEM:
        !           491:       return queued_subexp_p (XEXP (x, 0));
        !           492:     case MULT:
        !           493:     case PLUS:
        !           494:     case MINUS:
        !           495:       return queued_subexp_p (XEXP (x, 0))
        !           496:        || queued_subexp_p (XEXP (x, 1));
        !           497:     }
        !           498:   return 0;
        !           499: }
        !           500: 
        !           501: /* Perform all the pending incrementations.  */
        !           502: 
        !           503: void
        !           504: emit_queue ()
        !           505: {
        !           506:   register rtx p;
        !           507:   while (p = pending_chain)
        !           508:     {
        !           509:       QUEUED_INSN (p) = emit_insn (QUEUED_BODY (p));
        !           510:       pending_chain = QUEUED_NEXT (p);
        !           511:     }
        !           512: }
        !           513: 
        !           514: static void
        !           515: init_queue ()
        !           516: {
        !           517:   if (pending_chain)
        !           518:     abort ();
        !           519: }
        !           520: 
        !           521: /* Copy data from FROM to TO, where the machine modes are not the same.
        !           522:    Both modes may be integer, or both may be floating.
        !           523:    UNSIGNEDP should be nonzero if FROM is an unsigned type.
        !           524:    This causes zero-extension instead of sign-extension.  */
        !           525: 
        !           526: void
        !           527: convert_move (to, from, unsignedp)
        !           528:      register rtx to, from;
        !           529:      int unsignedp;
        !           530: {
        !           531:   enum machine_mode to_mode = GET_MODE (to);
        !           532:   enum machine_mode from_mode = GET_MODE (from);
        !           533:   int to_real = GET_MODE_CLASS (to_mode) == MODE_FLOAT;
        !           534:   int from_real = GET_MODE_CLASS (from_mode) == MODE_FLOAT;
        !           535:   enum insn_code code;
        !           536:   rtx libcall;
        !           537: 
        !           538:   /* rtx code for making an equivalent value.  */
        !           539:   enum rtx_code equiv_code = (unsignedp ? ZERO_EXTEND : SIGN_EXTEND);
        !           540: 
        !           541:   to = protect_from_queue (to, 1);
        !           542:   from = protect_from_queue (from, 0);
        !           543: 
        !           544:   if (to_real != from_real)
        !           545:     abort ();
        !           546: 
        !           547:   /* If FROM is a SUBREG that indicates that we have already done at least
        !           548:      the required extension, strip it.  We don't handle such SUBREGs as
        !           549:      TO here.  */
        !           550: 
        !           551:   if (GET_CODE (from) == SUBREG && SUBREG_PROMOTED_VAR_P (from)
        !           552:       && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (from)))
        !           553:          >= GET_MODE_SIZE (to_mode))
        !           554:       && SUBREG_PROMOTED_UNSIGNED_P (from) == unsignedp)
        !           555:     from = gen_lowpart (to_mode, from), from_mode = to_mode;
        !           556: 
        !           557:   if (GET_CODE (to) == SUBREG && SUBREG_PROMOTED_VAR_P (to))
        !           558:     abort ();
        !           559: 
        !           560:   if (to_mode == from_mode
        !           561:       || (from_mode == VOIDmode && CONSTANT_P (from)))
        !           562:     {
        !           563:       emit_move_insn (to, from);
        !           564:       return;
        !           565:     }
        !           566: 
        !           567:   if (to_real)
        !           568:     {
        !           569:       rtx value;
        !           570: 
        !           571: #ifdef HAVE_extendqfhf2
        !           572:       if (HAVE_extendqfsf2 && from_mode == QFmode && to_mode == HFmode)
        !           573:        {
        !           574:          emit_unop_insn (CODE_FOR_extendqfsf2, to, from, UNKNOWN);
        !           575:          return;
        !           576:        }
        !           577: #endif
        !           578: #ifdef HAVE_extendqfsf2
        !           579:       if (HAVE_extendqfsf2 && from_mode == QFmode && to_mode == SFmode)
        !           580:        {
        !           581:          emit_unop_insn (CODE_FOR_extendqfsf2, to, from, UNKNOWN);
        !           582:          return;
        !           583:        }
        !           584: #endif
        !           585: #ifdef HAVE_extendqfdf2
        !           586:       if (HAVE_extendqfdf2 && from_mode == QFmode && to_mode == DFmode)
        !           587:        {
        !           588:          emit_unop_insn (CODE_FOR_extendqfdf2, to, from, UNKNOWN);
        !           589:          return;
        !           590:        }
        !           591: #endif
        !           592: #ifdef HAVE_extendqfxf2
        !           593:       if (HAVE_extendqfxf2 && from_mode == QFmode && to_mode == XFmode)
        !           594:        {
        !           595:          emit_unop_insn (CODE_FOR_extendqfxf2, to, from, UNKNOWN);
        !           596:          return;
        !           597:        }
        !           598: #endif
        !           599: #ifdef HAVE_extendqftf2
        !           600:       if (HAVE_extendqftf2 && from_mode == QFmode && to_mode == TFmode)
        !           601:        {
        !           602:          emit_unop_insn (CODE_FOR_extendqftf2, to, from, UNKNOWN);
        !           603:          return;
        !           604:        }
        !           605: #endif
        !           606: 
        !           607: #ifdef HAVE_extendhfsf2
        !           608:       if (HAVE_extendhfsf2 && from_mode == HFmode && to_mode == SFmode)
        !           609:        {
        !           610:          emit_unop_insn (CODE_FOR_extendhfsf2, to, from, UNKNOWN);
        !           611:          return;
        !           612:        }
        !           613: #endif
        !           614: #ifdef HAVE_extendhfdf2
        !           615:       if (HAVE_extendhfdf2 && from_mode == HFmode && to_mode == DFmode)
        !           616:        {
        !           617:          emit_unop_insn (CODE_FOR_extendhfdf2, to, from, UNKNOWN);
        !           618:          return;
        !           619:        }
        !           620: #endif
        !           621: #ifdef HAVE_extendhfxf2
        !           622:       if (HAVE_extendhfxf2 && from_mode == HFmode && to_mode == XFmode)
        !           623:        {
        !           624:          emit_unop_insn (CODE_FOR_extendhfxf2, to, from, UNKNOWN);
        !           625:          return;
        !           626:        }
        !           627: #endif
        !           628: #ifdef HAVE_extendhftf2
        !           629:       if (HAVE_extendhftf2 && from_mode == HFmode && to_mode == TFmode)
        !           630:        {
        !           631:          emit_unop_insn (CODE_FOR_extendhftf2, to, from, UNKNOWN);
        !           632:          return;
        !           633:        }
        !           634: #endif
        !           635: 
        !           636: #ifdef HAVE_extendsfdf2
        !           637:       if (HAVE_extendsfdf2 && from_mode == SFmode && to_mode == DFmode)
        !           638:        {
        !           639:          emit_unop_insn (CODE_FOR_extendsfdf2, to, from, UNKNOWN);
        !           640:          return;
        !           641:        }
        !           642: #endif
        !           643: #ifdef HAVE_extendsfxf2
        !           644:       if (HAVE_extendsfxf2 && from_mode == SFmode && to_mode == XFmode)
        !           645:        {
        !           646:          emit_unop_insn (CODE_FOR_extendsfxf2, to, from, UNKNOWN);
        !           647:          return;
        !           648:        }
        !           649: #endif
        !           650: #ifdef HAVE_extendsftf2
        !           651:       if (HAVE_extendsftf2 && from_mode == SFmode && to_mode == TFmode)
        !           652:        {
        !           653:          emit_unop_insn (CODE_FOR_extendsftf2, to, from, UNKNOWN);
        !           654:          return;
        !           655:        }
        !           656: #endif
        !           657: #ifdef HAVE_extenddfxf2
        !           658:       if (HAVE_extenddfxf2 && from_mode == DFmode && to_mode == XFmode)
        !           659:        {
        !           660:          emit_unop_insn (CODE_FOR_extenddfxf2, to, from, UNKNOWN);
        !           661:          return;
        !           662:        }
        !           663: #endif
        !           664: #ifdef HAVE_extenddftf2
        !           665:       if (HAVE_extenddftf2 && from_mode == DFmode && to_mode == TFmode)
        !           666:        {
        !           667:          emit_unop_insn (CODE_FOR_extenddftf2, to, from, UNKNOWN);
        !           668:          return;
        !           669:        }
        !           670: #endif
        !           671: 
        !           672: #ifdef HAVE_trunchfqf2
        !           673:       if (HAVE_trunchfqf2 && from_mode == HFmode && to_mode == QFmode)
        !           674:        {
        !           675:          emit_unop_insn (CODE_FOR_trunchfqf2, to, from, UNKNOWN);
        !           676:          return;
        !           677:        }
        !           678: #endif
        !           679: #ifdef HAVE_truncsfqf2
        !           680:       if (HAVE_truncsfqf2 && from_mode == SFmode && to_mode == QFmode)
        !           681:        {
        !           682:          emit_unop_insn (CODE_FOR_truncsfqf2, to, from, UNKNOWN);
        !           683:          return;
        !           684:        }
        !           685: #endif
        !           686: #ifdef HAVE_truncdfqf2
        !           687:       if (HAVE_truncdfqf2 && from_mode == DFmode && to_mode == QFmode)
        !           688:        {
        !           689:          emit_unop_insn (CODE_FOR_truncdfqf2, to, from, UNKNOWN);
        !           690:          return;
        !           691:        }
        !           692: #endif
        !           693: #ifdef HAVE_truncxfqf2
        !           694:       if (HAVE_truncxfqf2 && from_mode == XFmode && to_mode == QFmode)
        !           695:        {
        !           696:          emit_unop_insn (CODE_FOR_truncxfqf2, to, from, UNKNOWN);
        !           697:          return;
        !           698:        }
        !           699: #endif
        !           700: #ifdef HAVE_trunctfqf2
        !           701:       if (HAVE_trunctfqf2 && from_mode == TFmode && to_mode == QFmode)
        !           702:        {
        !           703:          emit_unop_insn (CODE_FOR_trunctfqf2, to, from, UNKNOWN);
        !           704:          return;
        !           705:        }
        !           706: #endif
        !           707: #ifdef HAVE_truncsfhf2
        !           708:       if (HAVE_truncsfhf2 && from_mode == SFmode && to_mode == HFmode)
        !           709:        {
        !           710:          emit_unop_insn (CODE_FOR_truncsfhf2, to, from, UNKNOWN);
        !           711:          return;
        !           712:        }
        !           713: #endif
        !           714: #ifdef HAVE_truncdfhf2
        !           715:       if (HAVE_truncdfhf2 && from_mode == DFmode && to_mode == HFmode)
        !           716:        {
        !           717:          emit_unop_insn (CODE_FOR_truncdfhf2, to, from, UNKNOWN);
        !           718:          return;
        !           719:        }
        !           720: #endif
        !           721: #ifdef HAVE_truncxfhf2
        !           722:       if (HAVE_truncxfhf2 && from_mode == XFmode && to_mode == HFmode)
        !           723:        {
        !           724:          emit_unop_insn (CODE_FOR_truncxfhf2, to, from, UNKNOWN);
        !           725:          return;
        !           726:        }
        !           727: #endif
        !           728: #ifdef HAVE_trunctfhf2
        !           729:       if (HAVE_trunctfhf2 && from_mode == TFmode && to_mode == HFmode)
        !           730:        {
        !           731:          emit_unop_insn (CODE_FOR_trunctfhf2, to, from, UNKNOWN);
        !           732:          return;
        !           733:        }
        !           734: #endif
        !           735: #ifdef HAVE_truncdfsf2
        !           736:       if (HAVE_truncdfsf2 && from_mode == DFmode && to_mode == SFmode)
        !           737:        {
        !           738:          emit_unop_insn (CODE_FOR_truncdfsf2, to, from, UNKNOWN);
        !           739:          return;
        !           740:        }
        !           741: #endif
        !           742: #ifdef HAVE_truncxfsf2
        !           743:       if (HAVE_truncxfsf2 && from_mode == XFmode && to_mode == SFmode)
        !           744:        {
        !           745:          emit_unop_insn (CODE_FOR_truncxfsf2, to, from, UNKNOWN);
        !           746:          return;
        !           747:        }
        !           748: #endif
        !           749: #ifdef HAVE_trunctfsf2
        !           750:       if (HAVE_trunctfsf2 && from_mode == TFmode && to_mode == SFmode)
        !           751:        {
        !           752:          emit_unop_insn (CODE_FOR_trunctfsf2, to, from, UNKNOWN);
        !           753:          return;
        !           754:        }
        !           755: #endif
        !           756: #ifdef HAVE_truncxfdf2
        !           757:       if (HAVE_truncxfdf2 && from_mode == XFmode && to_mode == DFmode)
        !           758:        {
        !           759:          emit_unop_insn (CODE_FOR_truncxfdf2, to, from, UNKNOWN);
        !           760:          return;
        !           761:        }
        !           762: #endif
        !           763: #ifdef HAVE_trunctfdf2
        !           764:       if (HAVE_trunctfdf2 && from_mode == TFmode && to_mode == DFmode)
        !           765:        {
        !           766:          emit_unop_insn (CODE_FOR_trunctfdf2, to, from, UNKNOWN);
        !           767:          return;
        !           768:        }
        !           769: #endif
        !           770: 
        !           771:       libcall = (rtx) 0;
        !           772:       switch (from_mode)
        !           773:        {
        !           774:        case SFmode:
        !           775:          switch (to_mode)
        !           776:            {
        !           777:            case DFmode:
        !           778:              libcall = extendsfdf2_libfunc;
        !           779:              break;
        !           780: 
        !           781:            case XFmode:
        !           782:              libcall = extendsfxf2_libfunc;
        !           783:              break;
        !           784: 
        !           785:            case TFmode:
        !           786:              libcall = extendsftf2_libfunc;
        !           787:              break;
        !           788:            }
        !           789:          break;
        !           790: 
        !           791:        case DFmode:
        !           792:          switch (to_mode)
        !           793:            {
        !           794:            case SFmode:
        !           795:              libcall = truncdfsf2_libfunc;
        !           796:              break;
        !           797: 
        !           798:            case XFmode:
        !           799:              libcall = extenddfxf2_libfunc;
        !           800:              break;
        !           801: 
        !           802:            case TFmode:
        !           803:              libcall = extenddftf2_libfunc;
        !           804:              break;
        !           805:            }
        !           806:          break;
        !           807: 
        !           808:        case XFmode:
        !           809:          switch (to_mode)
        !           810:            {
        !           811:            case SFmode:
        !           812:              libcall = truncxfsf2_libfunc;
        !           813:              break;
        !           814: 
        !           815:            case DFmode:
        !           816:              libcall = truncxfdf2_libfunc;
        !           817:              break;
        !           818:            }
        !           819:          break;
        !           820: 
        !           821:        case TFmode:
        !           822:          switch (to_mode)
        !           823:            {
        !           824:            case SFmode:
        !           825:              libcall = trunctfsf2_libfunc;
        !           826:              break;
        !           827: 
        !           828:            case DFmode:
        !           829:              libcall = trunctfdf2_libfunc;
        !           830:              break;
        !           831:            }
        !           832:          break;
        !           833:        }
        !           834: 
        !           835:       if (libcall == (rtx) 0)
        !           836:        /* This conversion is not implemented yet.  */
        !           837:        abort ();
        !           838: 
        !           839:       value = emit_library_call_value (libcall, NULL_RTX, 1, to_mode,
        !           840:                                       1, from, from_mode);
        !           841:       emit_move_insn (to, value);
        !           842:       return;
        !           843:     }
        !           844: 
        !           845:   /* Now both modes are integers.  */
        !           846: 
        !           847:   /* Handle expanding beyond a word.  */
        !           848:   if (GET_MODE_BITSIZE (from_mode) < GET_MODE_BITSIZE (to_mode)
        !           849:       && GET_MODE_BITSIZE (to_mode) > BITS_PER_WORD)
        !           850:     {
        !           851:       rtx insns;
        !           852:       rtx lowpart;
        !           853:       rtx fill_value;
        !           854:       rtx lowfrom;
        !           855:       int i;
        !           856:       enum machine_mode lowpart_mode;
        !           857:       int nwords = CEIL (GET_MODE_SIZE (to_mode), UNITS_PER_WORD);
        !           858: 
        !           859:       /* Try converting directly if the insn is supported.  */
        !           860:       if ((code = can_extend_p (to_mode, from_mode, unsignedp))
        !           861:          != CODE_FOR_nothing)
        !           862:        {
        !           863:          /* If FROM is a SUBREG, put it into a register.  Do this
        !           864:             so that we always generate the same set of insns for
        !           865:             better cse'ing; if an intermediate assignment occurred,
        !           866:             we won't be doing the operation directly on the SUBREG.  */
        !           867:          if (optimize > 0 && GET_CODE (from) == SUBREG)
        !           868:            from = force_reg (from_mode, from);
        !           869:          emit_unop_insn (code, to, from, equiv_code);
        !           870:          return;
        !           871:        }
        !           872:       /* Next, try converting via full word.  */
        !           873:       else if (GET_MODE_BITSIZE (from_mode) < BITS_PER_WORD
        !           874:               && ((code = can_extend_p (to_mode, word_mode, unsignedp))
        !           875:                   != CODE_FOR_nothing))
        !           876:        {
        !           877:          if (GET_CODE (to) == REG)
        !           878:            emit_insn (gen_rtx (CLOBBER, VOIDmode, to));
        !           879:          convert_move (gen_lowpart (word_mode, to), from, unsignedp);
        !           880:          emit_unop_insn (code, to,
        !           881:                          gen_lowpart (word_mode, to), equiv_code);
        !           882:          return;
        !           883:        }
        !           884: 
        !           885:       /* No special multiword conversion insn; do it by hand.  */
        !           886:       start_sequence ();
        !           887: 
        !           888:       /* Get a copy of FROM widened to a word, if necessary.  */
        !           889:       if (GET_MODE_BITSIZE (from_mode) < BITS_PER_WORD)
        !           890:        lowpart_mode = word_mode;
        !           891:       else
        !           892:        lowpart_mode = from_mode;
        !           893: 
        !           894:       lowfrom = convert_to_mode (lowpart_mode, from, unsignedp);
        !           895: 
        !           896:       lowpart = gen_lowpart (lowpart_mode, to);
        !           897:       emit_move_insn (lowpart, lowfrom);
        !           898: 
        !           899:       /* Compute the value to put in each remaining word.  */
        !           900:       if (unsignedp)
        !           901:        fill_value = const0_rtx;
        !           902:       else
        !           903:        {
        !           904: #ifdef HAVE_slt
        !           905:          if (HAVE_slt
        !           906:              && insn_operand_mode[(int) CODE_FOR_slt][0] == word_mode
        !           907:              && STORE_FLAG_VALUE == -1)
        !           908:            {
        !           909:              emit_cmp_insn (lowfrom, const0_rtx, NE, NULL_RTX,
        !           910:                             lowpart_mode, 0, 0);
        !           911:              fill_value = gen_reg_rtx (word_mode);
        !           912:              emit_insn (gen_slt (fill_value));
        !           913:            }
        !           914:          else
        !           915: #endif
        !           916:            {
        !           917:              fill_value
        !           918:                = expand_shift (RSHIFT_EXPR, lowpart_mode, lowfrom,
        !           919:                                size_int (GET_MODE_BITSIZE (lowpart_mode) - 1),
        !           920:                                NULL_RTX, 0);
        !           921:              fill_value = convert_to_mode (word_mode, fill_value, 1);
        !           922:            }
        !           923:        }
        !           924: 
        !           925:       /* Fill the remaining words.  */
        !           926:       for (i = GET_MODE_SIZE (lowpart_mode) / UNITS_PER_WORD; i < nwords; i++)
        !           927:        {
        !           928:          int index = (WORDS_BIG_ENDIAN ? nwords - i - 1 : i);
        !           929:          rtx subword = operand_subword (to, index, 1, to_mode);
        !           930: 
        !           931:          if (subword == 0)
        !           932:            abort ();
        !           933: 
        !           934:          if (fill_value != subword)
        !           935:            emit_move_insn (subword, fill_value);
        !           936:        }
        !           937: 
        !           938:       insns = get_insns ();
        !           939:       end_sequence ();
        !           940: 
        !           941:       emit_no_conflict_block (insns, to, from, NULL_RTX,
        !           942:                              gen_rtx (equiv_code, to_mode, copy_rtx (from)));
        !           943:       return;
        !           944:     }
        !           945: 
        !           946:   /* Truncating multi-word to a word or less.  */
        !           947:   if (GET_MODE_BITSIZE (from_mode) > BITS_PER_WORD
        !           948:       && GET_MODE_BITSIZE (to_mode) <= BITS_PER_WORD)
        !           949:     {
        !           950:       if (!((GET_CODE (from) == MEM
        !           951:             && ! MEM_VOLATILE_P (from)
        !           952:             && direct_load[(int) to_mode]
        !           953:             && ! mode_dependent_address_p (XEXP (from, 0)))
        !           954:            || GET_CODE (from) == REG
        !           955:            || GET_CODE (from) == SUBREG))
        !           956:        from = force_reg (from_mode, from);
        !           957:       convert_move (to, gen_lowpart (word_mode, from), 0);
        !           958:       return;
        !           959:     }
        !           960: 
        !           961:   /* Handle pointer conversion */                      /* SPEE 900220 */
        !           962:   if (to_mode == PSImode)
        !           963:     {
        !           964:       if (from_mode != SImode)
        !           965:        from = convert_to_mode (SImode, from, unsignedp);
        !           966: 
        !           967: #ifdef HAVE_truncsipsi
        !           968:       if (HAVE_truncsipsi)
        !           969:        {
        !           970:          emit_unop_insn (CODE_FOR_truncsipsi, to, from, UNKNOWN);
        !           971:          return;
        !           972:        }
        !           973: #endif /* HAVE_truncsipsi */
        !           974:       abort ();
        !           975:     }
        !           976: 
        !           977:   if (from_mode == PSImode)
        !           978:     {
        !           979:       if (to_mode != SImode)
        !           980:        {
        !           981:          from = convert_to_mode (SImode, from, unsignedp);
        !           982:          from_mode = SImode;
        !           983:        }
        !           984:       else
        !           985:        {
        !           986: #ifdef HAVE_extendpsisi
        !           987:          if (HAVE_extendpsisi)
        !           988:            {
        !           989:              emit_unop_insn (CODE_FOR_extendpsisi, to, from, UNKNOWN);
        !           990:              return;
        !           991:            }
        !           992: #endif /* HAVE_extendpsisi */
        !           993:          abort ();
        !           994:        }
        !           995:     }
        !           996: 
        !           997:   /* Now follow all the conversions between integers
        !           998:      no more than a word long.  */
        !           999: 
        !          1000:   /* For truncation, usually we can just refer to FROM in a narrower mode.  */
        !          1001:   if (GET_MODE_BITSIZE (to_mode) < GET_MODE_BITSIZE (from_mode)
        !          1002:       && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (to_mode),
        !          1003:                                GET_MODE_BITSIZE (from_mode)))
        !          1004:     {
        !          1005:       if (!((GET_CODE (from) == MEM
        !          1006:             && ! MEM_VOLATILE_P (from)
        !          1007:             && direct_load[(int) to_mode]
        !          1008:             && ! mode_dependent_address_p (XEXP (from, 0)))
        !          1009:            || GET_CODE (from) == REG
        !          1010:            || GET_CODE (from) == SUBREG))
        !          1011:        from = force_reg (from_mode, from);
        !          1012:       emit_move_insn (to, gen_lowpart (to_mode, from));
        !          1013:       return;
        !          1014:     }
        !          1015: 
        !          1016:   /* Handle extension.  */
        !          1017:   if (GET_MODE_BITSIZE (to_mode) > GET_MODE_BITSIZE (from_mode))
        !          1018:     {
        !          1019:       /* Convert directly if that works.  */
        !          1020:       if ((code = can_extend_p (to_mode, from_mode, unsignedp))
        !          1021:          != CODE_FOR_nothing)
        !          1022:        {
        !          1023:          /* If FROM is a SUBREG, put it into a register.  Do this
        !          1024:             so that we always generate the same set of insns for
        !          1025:             better cse'ing; if an intermediate assignment occurred,
        !          1026:             we won't be doing the operation directly on the SUBREG.  */
        !          1027:          if (optimize > 0 && GET_CODE (from) == SUBREG)
        !          1028:            from = force_reg (from_mode, from);
        !          1029:          emit_unop_insn (code, to, from, equiv_code);
        !          1030:          return;
        !          1031:        }
        !          1032:       else
        !          1033:        {
        !          1034:          enum machine_mode intermediate;
        !          1035: 
        !          1036:          /* Search for a mode to convert via.  */
        !          1037:          for (intermediate = from_mode; intermediate != VOIDmode;
        !          1038:               intermediate = GET_MODE_WIDER_MODE (intermediate))
        !          1039:            if ((can_extend_p (to_mode, intermediate, unsignedp)
        !          1040:                 != CODE_FOR_nothing)
        !          1041:                && (can_extend_p (intermediate, from_mode, unsignedp)
        !          1042:                    != CODE_FOR_nothing))
        !          1043:              {
        !          1044:                convert_move (to, convert_to_mode (intermediate, from,
        !          1045:                                                   unsignedp), unsignedp);
        !          1046:                return;
        !          1047:              }
        !          1048: 
        !          1049:          /* No suitable intermediate mode.  */
        !          1050:          abort ();
        !          1051:        }
        !          1052:     }
        !          1053: 
        !          1054:   /* Support special truncate insns for certain modes.  */ 
        !          1055: 
        !          1056:   if (from_mode == DImode && to_mode == SImode)
        !          1057:     {
        !          1058: #ifdef HAVE_truncdisi2
        !          1059:       if (HAVE_truncdisi2)
        !          1060:        {
        !          1061:          emit_unop_insn (CODE_FOR_truncdisi2, to, from, UNKNOWN);
        !          1062:          return;
        !          1063:        }
        !          1064: #endif
        !          1065:       convert_move (to, force_reg (from_mode, from), unsignedp);
        !          1066:       return;
        !          1067:     }
        !          1068: 
        !          1069:   if (from_mode == DImode && to_mode == HImode)
        !          1070:     {
        !          1071: #ifdef HAVE_truncdihi2
        !          1072:       if (HAVE_truncdihi2)
        !          1073:        {
        !          1074:          emit_unop_insn (CODE_FOR_truncdihi2, to, from, UNKNOWN);
        !          1075:          return;
        !          1076:        }
        !          1077: #endif
        !          1078:       convert_move (to, force_reg (from_mode, from), unsignedp);
        !          1079:       return;
        !          1080:     }
        !          1081: 
        !          1082:   if (from_mode == DImode && to_mode == QImode)
        !          1083:     {
        !          1084: #ifdef HAVE_truncdiqi2
        !          1085:       if (HAVE_truncdiqi2)
        !          1086:        {
        !          1087:          emit_unop_insn (CODE_FOR_truncdiqi2, to, from, UNKNOWN);
        !          1088:          return;
        !          1089:        }
        !          1090: #endif
        !          1091:       convert_move (to, force_reg (from_mode, from), unsignedp);
        !          1092:       return;
        !          1093:     }
        !          1094: 
        !          1095:   if (from_mode == SImode && to_mode == HImode)
        !          1096:     {
        !          1097: #ifdef HAVE_truncsihi2
        !          1098:       if (HAVE_truncsihi2)
        !          1099:        {
        !          1100:          emit_unop_insn (CODE_FOR_truncsihi2, to, from, UNKNOWN);
        !          1101:          return;
        !          1102:        }
        !          1103: #endif
        !          1104:       convert_move (to, force_reg (from_mode, from), unsignedp);
        !          1105:       return;
        !          1106:     }
        !          1107: 
        !          1108:   if (from_mode == SImode && to_mode == QImode)
        !          1109:     {
        !          1110: #ifdef HAVE_truncsiqi2
        !          1111:       if (HAVE_truncsiqi2)
        !          1112:        {
        !          1113:          emit_unop_insn (CODE_FOR_truncsiqi2, to, from, UNKNOWN);
        !          1114:          return;
        !          1115:        }
        !          1116: #endif
        !          1117:       convert_move (to, force_reg (from_mode, from), unsignedp);
        !          1118:       return;
        !          1119:     }
        !          1120: 
        !          1121:   if (from_mode == HImode && to_mode == QImode)
        !          1122:     {
        !          1123: #ifdef HAVE_trunchiqi2
        !          1124:       if (HAVE_trunchiqi2)
        !          1125:        {
        !          1126:          emit_unop_insn (CODE_FOR_trunchiqi2, to, from, UNKNOWN);
        !          1127:          return;
        !          1128:        }
        !          1129: #endif
        !          1130:       convert_move (to, force_reg (from_mode, from), unsignedp);
        !          1131:       return;
        !          1132:     }
        !          1133: 
        !          1134:   /* Handle truncation of volatile memrefs, and so on;
        !          1135:      the things that couldn't be truncated directly,
        !          1136:      and for which there was no special instruction.  */
        !          1137:   if (GET_MODE_BITSIZE (to_mode) < GET_MODE_BITSIZE (from_mode))
        !          1138:     {
        !          1139:       rtx temp = force_reg (to_mode, gen_lowpart (to_mode, from));
        !          1140:       emit_move_insn (to, temp);
        !          1141:       return;
        !          1142:     }
        !          1143: 
        !          1144:   /* Mode combination is not recognized.  */
        !          1145:   abort ();
        !          1146: }
        !          1147: 
        !          1148: /* Return an rtx for a value that would result
        !          1149:    from converting X to mode MODE.
        !          1150:    Both X and MODE may be floating, or both integer.
        !          1151:    UNSIGNEDP is nonzero if X is an unsigned value.
        !          1152:    This can be done by referring to a part of X in place
        !          1153:    or by copying to a new temporary with conversion.
        !          1154: 
        !          1155:    This function *must not* call protect_from_queue
        !          1156:    except when putting X into an insn (in which case convert_move does it).  */
        !          1157: 
        !          1158: rtx
        !          1159: convert_to_mode (mode, x, unsignedp)
        !          1160:      enum machine_mode mode;
        !          1161:      rtx x;
        !          1162:      int unsignedp;
        !          1163: {
        !          1164:   return convert_modes (mode, VOIDmode, x, unsignedp);
        !          1165: }
        !          1166: 
        !          1167: /* Return an rtx for a value that would result
        !          1168:    from converting X from mode OLDMODE to mode MODE.
        !          1169:    Both modes may be floating, or both integer.
        !          1170:    UNSIGNEDP is nonzero if X is an unsigned value.
        !          1171: 
        !          1172:    This can be done by referring to a part of X in place
        !          1173:    or by copying to a new temporary with conversion.
        !          1174: 
        !          1175:    You can give VOIDmode for OLDMODE, if you are sure X has a nonvoid mode.
        !          1176: 
        !          1177:    This function *must not* call protect_from_queue
        !          1178:    except when putting X into an insn (in which case convert_move does it).  */
        !          1179: 
        !          1180: rtx
        !          1181: convert_modes (mode, oldmode, x, unsignedp)
        !          1182:      enum machine_mode mode, oldmode;
        !          1183:      rtx x;
        !          1184:      int unsignedp;
        !          1185: {
        !          1186:   register rtx temp;
        !          1187: 
        !          1188:   /* If FROM is a SUBREG that indicates that we have already done at least
        !          1189:      the required extension, strip it.  */
        !          1190: 
        !          1191:   if (GET_CODE (x) == SUBREG && SUBREG_PROMOTED_VAR_P (x)
        !          1192:       && GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) >= GET_MODE_SIZE (mode)
        !          1193:       && SUBREG_PROMOTED_UNSIGNED_P (x) == unsignedp)
        !          1194:     x = gen_lowpart (mode, x);
        !          1195: 
        !          1196:   if (GET_MODE (x) != VOIDmode)
        !          1197:     oldmode = GET_MODE (x);
        !          1198:  
        !          1199:   if (mode == oldmode)
        !          1200:     return x;
        !          1201: 
        !          1202:   /* There is one case that we must handle specially: If we are converting
        !          1203:      a CONST_INT into a mode whose size is twice HOST_BITS_PER_WIDE_INT and
        !          1204:      we are to interpret the constant as unsigned, gen_lowpart will do
        !          1205:      the wrong if the constant appears negative.  What we want to do is
        !          1206:      make the high-order word of the constant zero, not all ones.  */
        !          1207: 
        !          1208:   if (unsignedp && GET_MODE_CLASS (mode) == MODE_INT
        !          1209:       && GET_MODE_BITSIZE (mode) == 2 * HOST_BITS_PER_WIDE_INT
        !          1210:       && GET_CODE (x) == CONST_INT && INTVAL (x) < 0)
        !          1211:     return immed_double_const (INTVAL (x), (HOST_WIDE_INT) 0, mode);
        !          1212: 
        !          1213:   /* We can do this with a gen_lowpart if both desired and current modes
        !          1214:      are integer, and this is either a constant integer, a register, or a
        !          1215:      non-volatile MEM.  Except for the constant case where MODE is no
        !          1216:      wider than HOST_BITS_PER_WIDE_INT, we must be narrowing the operand.  */
        !          1217: 
        !          1218:   if ((GET_CODE (x) == CONST_INT
        !          1219:        && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
        !          1220:       || (GET_MODE_CLASS (mode) == MODE_INT
        !          1221:          && GET_MODE_CLASS (oldmode) == MODE_INT
        !          1222:          && (GET_CODE (x) == CONST_DOUBLE
        !          1223:              || (GET_MODE_SIZE (mode) <= GET_MODE_SIZE (oldmode)
        !          1224:                  && ((GET_CODE (x) == MEM && ! MEM_VOLATILE_P (x)
        !          1225:                       && direct_load[(int) mode])
        !          1226:                      || GET_CODE (x) == REG)))))
        !          1227:     {
        !          1228:       /* ?? If we don't know OLDMODE, we have to assume here that
        !          1229:         X does not need sign- or zero-extension.   This may not be
        !          1230:         the case, but it's the best we can do.  */
        !          1231:       if (GET_CODE (x) == CONST_INT && oldmode != VOIDmode
        !          1232:          && GET_MODE_SIZE (mode) > GET_MODE_SIZE (oldmode))
        !          1233:        {
        !          1234:          HOST_WIDE_INT val = INTVAL (x);
        !          1235:          int width = GET_MODE_BITSIZE (oldmode);
        !          1236: 
        !          1237:          /* We must sign or zero-extend in this case.  Start by
        !          1238:             zero-extending, then sign extend if we need to.  */
        !          1239:          val &= ((HOST_WIDE_INT) 1 << width) - 1;
        !          1240:          if (! unsignedp
        !          1241:              && (val & ((HOST_WIDE_INT) 1 << (width - 1))))
        !          1242:            val |= (HOST_WIDE_INT) (-1) << width;
        !          1243: 
        !          1244:          return GEN_INT (val);
        !          1245:        }
        !          1246: 
        !          1247:       return gen_lowpart (mode, x);
        !          1248:     }
        !          1249: 
        !          1250:   temp = gen_reg_rtx (mode);
        !          1251:   convert_move (temp, x, unsignedp);
        !          1252:   return temp;
        !          1253: }
        !          1254: 
        !          1255: /* Generate several move instructions to copy LEN bytes
        !          1256:    from block FROM to block TO.  (These are MEM rtx's with BLKmode).
        !          1257:    The caller must pass FROM and TO
        !          1258:     through protect_from_queue before calling.
        !          1259:    ALIGN (in bytes) is maximum alignment we can assume.  */
        !          1260: 
        !          1261: static void
        !          1262: move_by_pieces (to, from, len, align)
        !          1263:      rtx to, from;
        !          1264:      int len, align;
        !          1265: {
        !          1266:   struct move_by_pieces data;
        !          1267:   rtx to_addr = XEXP (to, 0), from_addr = XEXP (from, 0);
        !          1268:   int max_size = MOVE_MAX + 1;
        !          1269: 
        !          1270:   data.offset = 0;
        !          1271:   data.to_addr = to_addr;
        !          1272:   data.from_addr = from_addr;
        !          1273:   data.to = to;
        !          1274:   data.from = from;
        !          1275:   data.autinc_to
        !          1276:     = (GET_CODE (to_addr) == PRE_INC || GET_CODE (to_addr) == PRE_DEC
        !          1277:        || GET_CODE (to_addr) == POST_INC || GET_CODE (to_addr) == POST_DEC);
        !          1278:   data.autinc_from
        !          1279:     = (GET_CODE (from_addr) == PRE_INC || GET_CODE (from_addr) == PRE_DEC
        !          1280:        || GET_CODE (from_addr) == POST_INC
        !          1281:        || GET_CODE (from_addr) == POST_DEC);
        !          1282: 
        !          1283:   data.explicit_inc_from = 0;
        !          1284:   data.explicit_inc_to = 0;
        !          1285:   data.reverse
        !          1286:     = (GET_CODE (to_addr) == PRE_DEC || GET_CODE (to_addr) == POST_DEC);
        !          1287:   if (data.reverse) data.offset = len;
        !          1288:   data.len = len;
        !          1289: 
        !          1290:   /* If copying requires more than two move insns,
        !          1291:      copy addresses to registers (to make displacements shorter)
        !          1292:      and use post-increment if available.  */
        !          1293:   if (!(data.autinc_from && data.autinc_to)
        !          1294:       && move_by_pieces_ninsns (len, align) > 2)
        !          1295:     {
        !          1296: #ifdef HAVE_PRE_DECREMENT
        !          1297:       if (data.reverse && ! data.autinc_from)
        !          1298:        {
        !          1299:          data.from_addr = copy_addr_to_reg (plus_constant (from_addr, len));
        !          1300:          data.autinc_from = 1;
        !          1301:          data.explicit_inc_from = -1;
        !          1302:        }
        !          1303: #endif
        !          1304: #ifdef HAVE_POST_INCREMENT
        !          1305:       if (! data.autinc_from)
        !          1306:        {
        !          1307:          data.from_addr = copy_addr_to_reg (from_addr);
        !          1308:          data.autinc_from = 1;
        !          1309:          data.explicit_inc_from = 1;
        !          1310:        }
        !          1311: #endif
        !          1312:       if (!data.autinc_from && CONSTANT_P (from_addr))
        !          1313:        data.from_addr = copy_addr_to_reg (from_addr);
        !          1314: #ifdef HAVE_PRE_DECREMENT
        !          1315:       if (data.reverse && ! data.autinc_to)
        !          1316:        {
        !          1317:          data.to_addr = copy_addr_to_reg (plus_constant (to_addr, len));
        !          1318:          data.autinc_to = 1;
        !          1319:          data.explicit_inc_to = -1;
        !          1320:        }
        !          1321: #endif
        !          1322: #ifdef HAVE_POST_INCREMENT
        !          1323:       if (! data.reverse && ! data.autinc_to)
        !          1324:        {
        !          1325:          data.to_addr = copy_addr_to_reg (to_addr);
        !          1326:          data.autinc_to = 1;
        !          1327:          data.explicit_inc_to = 1;
        !          1328:        }
        !          1329: #endif
        !          1330:       if (!data.autinc_to && CONSTANT_P (to_addr))
        !          1331:        data.to_addr = copy_addr_to_reg (to_addr);
        !          1332:     }
        !          1333: 
        !          1334:   if (! (STRICT_ALIGNMENT || SLOW_UNALIGNED_ACCESS)
        !          1335:       || align > MOVE_MAX || align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT)
        !          1336:     align = MOVE_MAX;
        !          1337: 
        !          1338:   /* First move what we can in the largest integer mode, then go to
        !          1339:      successively smaller modes.  */
        !          1340: 
        !          1341:   while (max_size > 1)
        !          1342:     {
        !          1343:       enum machine_mode mode = VOIDmode, tmode;
        !          1344:       enum insn_code icode;
        !          1345: 
        !          1346:       for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
        !          1347:           tmode != VOIDmode; tmode = GET_MODE_WIDER_MODE (tmode))
        !          1348:        if (GET_MODE_SIZE (tmode) < max_size)
        !          1349:          mode = tmode;
        !          1350: 
        !          1351:       if (mode == VOIDmode)
        !          1352:        break;
        !          1353: 
        !          1354:       icode = mov_optab->handlers[(int) mode].insn_code;
        !          1355:       if (icode != CODE_FOR_nothing
        !          1356:          && align >= MIN (BIGGEST_ALIGNMENT / BITS_PER_UNIT,
        !          1357:                           GET_MODE_SIZE (mode)))
        !          1358:        move_by_pieces_1 (GEN_FCN (icode), mode, &data);
        !          1359: 
        !          1360:       max_size = GET_MODE_SIZE (mode);
        !          1361:     }
        !          1362: 
        !          1363:   /* The code above should have handled everything.  */
        !          1364:   if (data.len != 0)
        !          1365:     abort ();
        !          1366: }
        !          1367: 
        !          1368: /* Return number of insns required to move L bytes by pieces.
        !          1369:    ALIGN (in bytes) is maximum alignment we can assume.  */
        !          1370: 
        !          1371: static int
        !          1372: move_by_pieces_ninsns (l, align)
        !          1373:      unsigned int l;
        !          1374:      int align;
        !          1375: {
        !          1376:   register int n_insns = 0;
        !          1377:   int max_size = MOVE_MAX + 1;
        !          1378: 
        !          1379:   if (! (STRICT_ALIGNMENT || SLOW_UNALIGNED_ACCESS)
        !          1380:       || align > MOVE_MAX || align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT)
        !          1381:     align = MOVE_MAX;
        !          1382: 
        !          1383:   while (max_size > 1)
        !          1384:     {
        !          1385:       enum machine_mode mode = VOIDmode, tmode;
        !          1386:       enum insn_code icode;
        !          1387: 
        !          1388:       for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
        !          1389:           tmode != VOIDmode; tmode = GET_MODE_WIDER_MODE (tmode))
        !          1390:        if (GET_MODE_SIZE (tmode) < max_size)
        !          1391:          mode = tmode;
        !          1392: 
        !          1393:       if (mode == VOIDmode)
        !          1394:        break;
        !          1395: 
        !          1396:       icode = mov_optab->handlers[(int) mode].insn_code;
        !          1397:       if (icode != CODE_FOR_nothing
        !          1398:          && align >= MIN (BIGGEST_ALIGNMENT / BITS_PER_UNIT,
        !          1399:                           GET_MODE_SIZE (mode)))
        !          1400:        n_insns += l / GET_MODE_SIZE (mode), l %= GET_MODE_SIZE (mode);
        !          1401: 
        !          1402:       max_size = GET_MODE_SIZE (mode);
        !          1403:     }
        !          1404: 
        !          1405:   return n_insns;
        !          1406: }
        !          1407: 
        !          1408: /* Subroutine of move_by_pieces.  Move as many bytes as appropriate
        !          1409:    with move instructions for mode MODE.  GENFUN is the gen_... function
        !          1410:    to make a move insn for that mode.  DATA has all the other info.  */
        !          1411: 
        !          1412: static void
        !          1413: move_by_pieces_1 (genfun, mode, data)
        !          1414:      rtx (*genfun) ();
        !          1415:      enum machine_mode mode;
        !          1416:      struct move_by_pieces *data;
        !          1417: {
        !          1418:   register int size = GET_MODE_SIZE (mode);
        !          1419:   register rtx to1, from1;
        !          1420: 
        !          1421:   while (data->len >= size)
        !          1422:     {
        !          1423:       if (data->reverse) data->offset -= size;
        !          1424: 
        !          1425:       to1 = (data->autinc_to
        !          1426:             ? gen_rtx (MEM, mode, data->to_addr)
        !          1427:             : change_address (data->to, mode,
        !          1428:                               plus_constant (data->to_addr, data->offset)));
        !          1429:       from1 =
        !          1430:        (data->autinc_from
        !          1431:         ? gen_rtx (MEM, mode, data->from_addr)
        !          1432:         : change_address (data->from, mode,
        !          1433:                           plus_constant (data->from_addr, data->offset)));
        !          1434: 
        !          1435: #ifdef HAVE_PRE_DECREMENT
        !          1436:       if (data->explicit_inc_to < 0)
        !          1437:        emit_insn (gen_add2_insn (data->to_addr, GEN_INT (-size)));
        !          1438:       if (data->explicit_inc_from < 0)
        !          1439:        emit_insn (gen_add2_insn (data->from_addr, GEN_INT (-size)));
        !          1440: #endif
        !          1441: 
        !          1442:       emit_insn ((*genfun) (to1, from1));
        !          1443: #ifdef HAVE_POST_INCREMENT
        !          1444:       if (data->explicit_inc_to > 0)
        !          1445:        emit_insn (gen_add2_insn (data->to_addr, GEN_INT (size)));
        !          1446:       if (data->explicit_inc_from > 0)
        !          1447:        emit_insn (gen_add2_insn (data->from_addr, GEN_INT (size)));
        !          1448: #endif
        !          1449: 
        !          1450:       if (! data->reverse) data->offset += size;
        !          1451: 
        !          1452:       data->len -= size;
        !          1453:     }
        !          1454: }
        !          1455: 
        !          1456: /* Emit code to move a block Y to a block X.
        !          1457:    This may be done with string-move instructions,
        !          1458:    with multiple scalar move instructions, or with a library call.
        !          1459: 
        !          1460:    Both X and Y must be MEM rtx's (perhaps inside VOLATILE)
        !          1461:    with mode BLKmode.
        !          1462:    SIZE is an rtx that says how long they are.
        !          1463:    ALIGN is the maximum alignment we can assume they have,
        !          1464:    measured in bytes.  */
        !          1465: 
        !          1466: void
        !          1467: emit_block_move (x, y, size, align)
        !          1468:      rtx x, y;
        !          1469:      rtx size;
        !          1470:      int align;
        !          1471: {
        !          1472:   if (GET_MODE (x) != BLKmode)
        !          1473:     abort ();
        !          1474: 
        !          1475:   if (GET_MODE (y) != BLKmode)
        !          1476:     abort ();
        !          1477: 
        !          1478:   x = protect_from_queue (x, 1);
        !          1479:   y = protect_from_queue (y, 0);
        !          1480:   size = protect_from_queue (size, 0);
        !          1481: 
        !          1482:   if (GET_CODE (x) != MEM)
        !          1483:     abort ();
        !          1484:   if (GET_CODE (y) != MEM)
        !          1485:     abort ();
        !          1486:   if (size == 0)
        !          1487:     abort ();
        !          1488: 
        !          1489:   if (GET_CODE (size) == CONST_INT
        !          1490:       && (move_by_pieces_ninsns (INTVAL (size), align) < MOVE_RATIO))
        !          1491:     move_by_pieces (x, y, INTVAL (size), align);
        !          1492:   else
        !          1493:     {
        !          1494:       /* Try the most limited insn first, because there's no point
        !          1495:         including more than one in the machine description unless
        !          1496:         the more limited one has some advantage.  */
        !          1497: 
        !          1498:       rtx opalign = GEN_INT (align);
        !          1499:       enum machine_mode mode;
        !          1500: 
        !          1501:       for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
        !          1502:           mode = GET_MODE_WIDER_MODE (mode))
        !          1503:        {
        !          1504:          enum insn_code code = movstr_optab[(int) mode];
        !          1505: 
        !          1506:          if (code != CODE_FOR_nothing
        !          1507:              /* We don't need MODE to be narrower than BITS_PER_HOST_WIDE_INT
        !          1508:                 here because if SIZE is less than the mode mask, as it is
        !          1509:                 returned by the macro, it will definitely be less than the
        !          1510:                 actual mode mask.  */
        !          1511:              && (unsigned HOST_WIDE_INT) INTVAL (size) <= GET_MODE_MASK (mode)
        !          1512:              && (insn_operand_predicate[(int) code][0] == 0
        !          1513:                  || (*insn_operand_predicate[(int) code][0]) (x, BLKmode))
        !          1514:              && (insn_operand_predicate[(int) code][1] == 0
        !          1515:                  || (*insn_operand_predicate[(int) code][1]) (y, BLKmode))
        !          1516:              && (insn_operand_predicate[(int) code][3] == 0
        !          1517:                  || (*insn_operand_predicate[(int) code][3]) (opalign,
        !          1518:                                                               VOIDmode)))
        !          1519:            {
        !          1520:              rtx op2;
        !          1521:              rtx last = get_last_insn ();
        !          1522:              rtx pat;
        !          1523: 
        !          1524:              op2 = convert_to_mode (mode, size, 1);
        !          1525:              if (insn_operand_predicate[(int) code][2] != 0
        !          1526:                  && ! (*insn_operand_predicate[(int) code][2]) (op2, mode))
        !          1527:                op2 = copy_to_mode_reg (mode, op2);
        !          1528: 
        !          1529:              pat = GEN_FCN ((int) code) (x, y, op2, opalign);
        !          1530:              if (pat)
        !          1531:                {
        !          1532:                  emit_insn (pat);
        !          1533:                  return;
        !          1534:                }
        !          1535:              else
        !          1536:                delete_insns_since (last);
        !          1537:            }
        !          1538:        }
        !          1539: 
        !          1540: #ifdef TARGET_MEM_FUNCTIONS
        !          1541:       emit_library_call (memcpy_libfunc, 0,
        !          1542:                         VOIDmode, 3, XEXP (x, 0), Pmode,
        !          1543:                         XEXP (y, 0), Pmode,
        !          1544:                         convert_to_mode (TYPE_MODE (sizetype), size,
        !          1545:                                          TREE_UNSIGNED (sizetype)),
        !          1546:                         TYPE_MODE (sizetype));
        !          1547: #else
        !          1548:       emit_library_call (bcopy_libfunc, 0,
        !          1549:                         VOIDmode, 3, XEXP (y, 0), Pmode,
        !          1550:                         XEXP (x, 0), Pmode,
        !          1551:                         convert_to_mode (TYPE_MODE (sizetype), size,
        !          1552:                                          TREE_UNSIGNED (sizetype)),
        !          1553:                         TYPE_MODE (sizetype));
        !          1554: #endif
        !          1555:     }
        !          1556: }
        !          1557: 
        !          1558: /* Copy all or part of a value X into registers starting at REGNO.
        !          1559:    The number of registers to be filled is NREGS.  */
        !          1560: 
        !          1561: void
        !          1562: move_block_to_reg (regno, x, nregs, mode)
        !          1563:      int regno;
        !          1564:      rtx x;
        !          1565:      int nregs;
        !          1566:      enum machine_mode mode;
        !          1567: {
        !          1568:   int i;
        !          1569:   rtx pat, last;
        !          1570: 
        !          1571:   if (CONSTANT_P (x) && ! LEGITIMATE_CONSTANT_P (x))
        !          1572:     x = validize_mem (force_const_mem (mode, x));
        !          1573: 
        !          1574:   /* See if the machine can do this with a load multiple insn.  */
        !          1575: #ifdef HAVE_load_multiple
        !          1576:   if (HAVE_load_multiple)
        !          1577:     {
        !          1578:       last = get_last_insn ();
        !          1579:       pat = gen_load_multiple (gen_rtx (REG, word_mode, regno), x,
        !          1580:                               GEN_INT (nregs));
        !          1581:       if (pat)
        !          1582:        {
        !          1583:          emit_insn (pat);
        !          1584:          return;
        !          1585:        }
        !          1586:       else
        !          1587:        delete_insns_since (last);
        !          1588:     }
        !          1589: #endif
        !          1590: 
        !          1591:   for (i = 0; i < nregs; i++)
        !          1592:     emit_move_insn (gen_rtx (REG, word_mode, regno + i),
        !          1593:                    operand_subword_force (x, i, mode));
        !          1594: }
        !          1595: 
        !          1596: /* Copy all or part of a BLKmode value X out of registers starting at REGNO.
        !          1597:    The number of registers to be filled is NREGS.  SIZE indicates the number
        !          1598:    of bytes in the object X.  */
        !          1599: 
        !          1600: 
        !          1601: void
        !          1602: move_block_from_reg (regno, x, nregs, size)
        !          1603:      int regno;
        !          1604:      rtx x;
        !          1605:      int nregs;
        !          1606:      int size;
        !          1607: {
        !          1608:   int i;
        !          1609:   rtx pat, last;
        !          1610: 
        !          1611:   /* Blocks smaller than a word on a BYTES_BIG_ENDIAN machine must be aligned
        !          1612:      to the left before storing to memory.  */
        !          1613:   if (size < UNITS_PER_WORD && BYTES_BIG_ENDIAN)
        !          1614:     {
        !          1615:       rtx tem = operand_subword (x, 0, 1, BLKmode);
        !          1616:       rtx shift;
        !          1617: 
        !          1618:       if (tem == 0)
        !          1619:        abort ();
        !          1620: 
        !          1621:       shift = expand_shift (LSHIFT_EXPR, word_mode,
        !          1622:                            gen_rtx (REG, word_mode, regno),
        !          1623:                            build_int_2 ((UNITS_PER_WORD - size)
        !          1624:                                         * BITS_PER_UNIT, 0), NULL_RTX, 0);
        !          1625:       emit_move_insn (tem, shift);
        !          1626:       return;
        !          1627:     }
        !          1628: 
        !          1629:   /* See if the machine can do this with a store multiple insn.  */
        !          1630: #ifdef HAVE_store_multiple
        !          1631:   if (HAVE_store_multiple)
        !          1632:     {
        !          1633:       last = get_last_insn ();
        !          1634:       pat = gen_store_multiple (x, gen_rtx (REG, word_mode, regno),
        !          1635:                                GEN_INT (nregs));
        !          1636:       if (pat)
        !          1637:        {
        !          1638:          emit_insn (pat);
        !          1639:          return;
        !          1640:        }
        !          1641:       else
        !          1642:        delete_insns_since (last);
        !          1643:     }
        !          1644: #endif
        !          1645: 
        !          1646:   for (i = 0; i < nregs; i++)
        !          1647:     {
        !          1648:       rtx tem = operand_subword (x, i, 1, BLKmode);
        !          1649: 
        !          1650:       if (tem == 0)
        !          1651:        abort ();
        !          1652: 
        !          1653:       emit_move_insn (tem, gen_rtx (REG, word_mode, regno + i));
        !          1654:     }
        !          1655: }
        !          1656: 
        !          1657: /* Mark NREGS consecutive regs, starting at REGNO, as being live now.  */
        !          1658: 
        !          1659: void
        !          1660: use_regs (regno, nregs)
        !          1661:      int regno;
        !          1662:      int nregs;
        !          1663: {
        !          1664:   int i;
        !          1665: 
        !          1666:   for (i = 0; i < nregs; i++)
        !          1667:     emit_insn (gen_rtx (USE, VOIDmode, gen_rtx (REG, word_mode, regno + i)));
        !          1668: }
        !          1669: 
        !          1670: /* Mark the instructions since PREV as a libcall block.
        !          1671:    Add REG_LIBCALL to PREV and add a REG_RETVAL to the most recent insn.  */
        !          1672: 
        !          1673: static void
        !          1674: group_insns (prev)
        !          1675:      rtx prev;
        !          1676: {
        !          1677:   rtx insn_first;
        !          1678:   rtx insn_last;
        !          1679: 
        !          1680:   /* Find the instructions to mark */
        !          1681:   if (prev)
        !          1682:     insn_first = NEXT_INSN (prev);
        !          1683:   else
        !          1684:     insn_first = get_insns ();
        !          1685: 
        !          1686:   insn_last = get_last_insn ();
        !          1687: 
        !          1688:   REG_NOTES (insn_last) = gen_rtx (INSN_LIST, REG_RETVAL, insn_first,
        !          1689:                                   REG_NOTES (insn_last));
        !          1690: 
        !          1691:   REG_NOTES (insn_first) = gen_rtx (INSN_LIST, REG_LIBCALL, insn_last,
        !          1692:                                    REG_NOTES (insn_first));
        !          1693: }
        !          1694: 
        !          1695: /* Write zeros through the storage of OBJECT.
        !          1696:    If OBJECT has BLKmode, SIZE is its length in bytes.  */
        !          1697: 
        !          1698: void
        !          1699: clear_storage (object, size)
        !          1700:      rtx object;
        !          1701:      int size;
        !          1702: {
        !          1703:   if (GET_MODE (object) == BLKmode)
        !          1704:     {
        !          1705: #ifdef TARGET_MEM_FUNCTIONS
        !          1706:       emit_library_call (memset_libfunc, 0,
        !          1707:                         VOIDmode, 3,
        !          1708:                         XEXP (object, 0), Pmode, const0_rtx, Pmode,
        !          1709:                         GEN_INT (size), Pmode);
        !          1710: #else
        !          1711:       emit_library_call (bzero_libfunc, 0,
        !          1712:                         VOIDmode, 2,
        !          1713:                         XEXP (object, 0), Pmode,
        !          1714:                         GEN_INT (size), Pmode);
        !          1715: #endif
        !          1716:     }
        !          1717:   else
        !          1718:     emit_move_insn (object, const0_rtx);
        !          1719: }
        !          1720: 
        !          1721: /* Generate code to copy Y into X.
        !          1722:    Both Y and X must have the same mode, except that
        !          1723:    Y can be a constant with VOIDmode.
        !          1724:    This mode cannot be BLKmode; use emit_block_move for that.
        !          1725: 
        !          1726:    Return the last instruction emitted.  */
        !          1727: 
        !          1728: rtx
        !          1729: emit_move_insn (x, y)
        !          1730:      rtx x, y;
        !          1731: {
        !          1732:   enum machine_mode mode = GET_MODE (x);
        !          1733:   enum machine_mode submode;
        !          1734:   enum mode_class class = GET_MODE_CLASS (mode);
        !          1735:   int i;
        !          1736: 
        !          1737:   x = protect_from_queue (x, 1);
        !          1738:   y = protect_from_queue (y, 0);
        !          1739: 
        !          1740:   if (mode == BLKmode || (GET_MODE (y) != mode && GET_MODE (y) != VOIDmode))
        !          1741:     abort ();
        !          1742: 
        !          1743:   if (CONSTANT_P (y) && ! LEGITIMATE_CONSTANT_P (y))
        !          1744:     y = force_const_mem (mode, y);
        !          1745: 
        !          1746:   /* If X or Y are memory references, verify that their addresses are valid
        !          1747:      for the machine.  */
        !          1748:   if (GET_CODE (x) == MEM
        !          1749:       && ((! memory_address_p (GET_MODE (x), XEXP (x, 0))
        !          1750:           && ! push_operand (x, GET_MODE (x)))
        !          1751:          || (flag_force_addr
        !          1752:              && CONSTANT_ADDRESS_P (XEXP (x, 0)))))
        !          1753:     x = change_address (x, VOIDmode, XEXP (x, 0));
        !          1754: 
        !          1755:   if (GET_CODE (y) == MEM
        !          1756:       && (! memory_address_p (GET_MODE (y), XEXP (y, 0))
        !          1757:          || (flag_force_addr
        !          1758:              && CONSTANT_ADDRESS_P (XEXP (y, 0)))))
        !          1759:     y = change_address (y, VOIDmode, XEXP (y, 0));
        !          1760: 
        !          1761:   if (mode == BLKmode)
        !          1762:     abort ();
        !          1763: 
        !          1764:   return emit_move_insn_1 (x, y);
        !          1765: }
        !          1766: 
        !          1767: /* Low level part of emit_move_insn.
        !          1768:    Called just like emit_move_insn, but assumes X and Y
        !          1769:    are basically valid.  */
        !          1770: 
        !          1771: rtx
        !          1772: emit_move_insn_1 (x, y)
        !          1773:      rtx x, y;
        !          1774: {
        !          1775:   enum machine_mode mode = GET_MODE (x);
        !          1776:   enum machine_mode submode;
        !          1777:   enum mode_class class = GET_MODE_CLASS (mode);
        !          1778:   int i;
        !          1779: 
        !          1780:   if (class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT)
        !          1781:     submode = mode_for_size (GET_MODE_UNIT_SIZE (mode) * BITS_PER_UNIT,
        !          1782:                             (class == MODE_COMPLEX_INT
        !          1783:                              ? MODE_INT : MODE_FLOAT),
        !          1784:                             0);
        !          1785: 
        !          1786:   if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
        !          1787:     return
        !          1788:       emit_insn (GEN_FCN (mov_optab->handlers[(int) mode].insn_code) (x, y));
        !          1789: 
        !          1790:   /* Expand complex moves by moving real part and imag part, if possible.  */
        !          1791:   else if ((class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT)
        !          1792:           && submode != BLKmode
        !          1793:           && (mov_optab->handlers[(int) submode].insn_code
        !          1794:               != CODE_FOR_nothing))
        !          1795:     {
        !          1796:       /* Don't split destination if it is a stack push.  */
        !          1797:       int stack = push_operand (x, GET_MODE (x));
        !          1798:       rtx prev = get_last_insn ();
        !          1799: 
        !          1800:       /* Tell flow that the whole of the destination is being set.  */
        !          1801:       if (GET_CODE (x) == REG)
        !          1802:        emit_insn (gen_rtx (CLOBBER, VOIDmode, x));
        !          1803: 
        !          1804:       /* If this is a stack, push the highpart first, so it
        !          1805:         will be in the argument order.
        !          1806: 
        !          1807:         In that case, change_address is used only to convert
        !          1808:         the mode, not to change the address.  */
        !          1809:       if (stack)
        !          1810:        {
        !          1811:          /* Note that the real part always precedes the imag part in memory
        !          1812:             regardless of machine's endianness.  */
        !          1813: #ifdef STACK_GROWS_DOWNWARD
        !          1814:          emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
        !          1815:                     (gen_rtx (MEM, submode, (XEXP (x, 0))),
        !          1816:                      gen_imagpart (submode, y)));
        !          1817:          emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
        !          1818:                     (gen_rtx (MEM, submode, (XEXP (x, 0))),
        !          1819:                      gen_realpart (submode, y)));
        !          1820: #else
        !          1821:          emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
        !          1822:                     (gen_rtx (MEM, submode, (XEXP (x, 0))),
        !          1823:                      gen_realpart (submode, y)));
        !          1824:          emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
        !          1825:                     (gen_rtx (MEM, submode, (XEXP (x, 0))),
        !          1826:                      gen_imagpart (submode, y)));
        !          1827: #endif
        !          1828:        }
        !          1829:       else
        !          1830:        {
        !          1831:          emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
        !          1832:                     (gen_highpart (submode, x), gen_highpart (submode, y)));
        !          1833:          emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
        !          1834:                     (gen_lowpart (submode, x), gen_lowpart (submode, y)));
        !          1835:        }
        !          1836: 
        !          1837:       if (GET_CODE (x) != CONCAT)
        !          1838:        /* If X is a CONCAT, we got insns like RD = RS, ID = IS,
        !          1839:           each with a separate pseudo as destination.
        !          1840:           It's not correct for flow to treat them as a unit.  */
        !          1841:        group_insns (prev);
        !          1842: 
        !          1843:       return get_last_insn ();
        !          1844:     }
        !          1845: 
        !          1846:   /* This will handle any multi-word mode that lacks a move_insn pattern.
        !          1847:      However, you will get better code if you define such patterns,
        !          1848:      even if they must turn into multiple assembler instructions.  */
        !          1849:   else if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
        !          1850:     {
        !          1851:       rtx last_insn = 0;
        !          1852:       rtx prev_insn = get_last_insn ();
        !          1853: 
        !          1854:       for (i = 0;
        !          1855:           i < (GET_MODE_SIZE (mode)  + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD;
        !          1856:           i++)
        !          1857:        {
        !          1858:          rtx xpart = operand_subword (x, i, 1, mode);
        !          1859:          rtx ypart = operand_subword (y, i, 1, mode);
        !          1860: 
        !          1861:          /* If we can't get a part of Y, put Y into memory if it is a
        !          1862:             constant.  Otherwise, force it into a register.  If we still
        !          1863:             can't get a part of Y, abort.  */
        !          1864:          if (ypart == 0 && CONSTANT_P (y))
        !          1865:            {
        !          1866:              y = force_const_mem (mode, y);
        !          1867:              ypart = operand_subword (y, i, 1, mode);
        !          1868:            }
        !          1869:          else if (ypart == 0)
        !          1870:            ypart = operand_subword_force (y, i, mode);
        !          1871: 
        !          1872:          if (xpart == 0 || ypart == 0)
        !          1873:            abort ();
        !          1874: 
        !          1875:          last_insn = emit_move_insn (xpart, ypart);
        !          1876:        }
        !          1877:       /* Mark these insns as a libcall block.  */
        !          1878:       group_insns (prev_insn);
        !          1879: 
        !          1880:       return last_insn;
        !          1881:     }
        !          1882:   else
        !          1883:     abort ();
        !          1884: }
        !          1885: 
        !          1886: /* Pushing data onto the stack.  */
        !          1887: 
        !          1888: /* Push a block of length SIZE (perhaps variable)
        !          1889:    and return an rtx to address the beginning of the block.
        !          1890:    Note that it is not possible for the value returned to be a QUEUED.
        !          1891:    The value may be virtual_outgoing_args_rtx.
        !          1892: 
        !          1893:    EXTRA is the number of bytes of padding to push in addition to SIZE.
        !          1894:    BELOW nonzero means this padding comes at low addresses;
        !          1895:    otherwise, the padding comes at high addresses.  */
        !          1896: 
        !          1897: rtx
        !          1898: push_block (size, extra, below)
        !          1899:      rtx size;
        !          1900:      int extra, below;
        !          1901: {
        !          1902:   register rtx temp;
        !          1903:   if (CONSTANT_P (size))
        !          1904:     anti_adjust_stack (plus_constant (size, extra));
        !          1905:   else if (GET_CODE (size) == REG && extra == 0)
        !          1906:     anti_adjust_stack (size);
        !          1907:   else
        !          1908:     {
        !          1909:       rtx temp = copy_to_mode_reg (Pmode, size);
        !          1910:       if (extra != 0)
        !          1911:        temp = expand_binop (Pmode, add_optab, temp, GEN_INT (extra),
        !          1912:                             temp, 0, OPTAB_LIB_WIDEN);
        !          1913:       anti_adjust_stack (temp);
        !          1914:     }
        !          1915: 
        !          1916: #ifdef STACK_GROWS_DOWNWARD
        !          1917:   temp = virtual_outgoing_args_rtx;
        !          1918:   if (extra != 0 && below)
        !          1919:     temp = plus_constant (temp, extra);
        !          1920: #else
        !          1921:   if (GET_CODE (size) == CONST_INT)
        !          1922:     temp = plus_constant (virtual_outgoing_args_rtx,
        !          1923:                          - INTVAL (size) - (below ? 0 : extra));
        !          1924:   else if (extra != 0 && !below)
        !          1925:     temp = gen_rtx (PLUS, Pmode, virtual_outgoing_args_rtx,
        !          1926:                    negate_rtx (Pmode, plus_constant (size, extra)));
        !          1927:   else
        !          1928:     temp = gen_rtx (PLUS, Pmode, virtual_outgoing_args_rtx,
        !          1929:                    negate_rtx (Pmode, size));
        !          1930: #endif
        !          1931: 
        !          1932:   return memory_address (GET_CLASS_NARROWEST_MODE (MODE_INT), temp);
        !          1933: }
        !          1934: 
        !          1935: rtx
        !          1936: gen_push_operand ()
        !          1937: {
        !          1938:   return gen_rtx (STACK_PUSH_CODE, Pmode, stack_pointer_rtx);
        !          1939: }
        !          1940: 
        !          1941: /* Generate code to push X onto the stack, assuming it has mode MODE and
        !          1942:    type TYPE.
        !          1943:    MODE is redundant except when X is a CONST_INT (since they don't
        !          1944:    carry mode info).
        !          1945:    SIZE is an rtx for the size of data to be copied (in bytes),
        !          1946:    needed only if X is BLKmode.
        !          1947: 
        !          1948:    ALIGN (in bytes) is maximum alignment we can assume.
        !          1949: 
        !          1950:    If PARTIAL and REG are both nonzero, then copy that many of the first
        !          1951:    words of X into registers starting with REG, and push the rest of X.
        !          1952:    The amount of space pushed is decreased by PARTIAL words,
        !          1953:    rounded *down* to a multiple of PARM_BOUNDARY.
        !          1954:    REG must be a hard register in this case.
        !          1955:    If REG is zero but PARTIAL is not, take any all others actions for an
        !          1956:    argument partially in registers, but do not actually load any
        !          1957:    registers.
        !          1958: 
        !          1959:    EXTRA is the amount in bytes of extra space to leave next to this arg.
        !          1960:    This is ignored if an argument block has already been allocated.
        !          1961: 
        !          1962:    On a machine that lacks real push insns, ARGS_ADDR is the address of
        !          1963:    the bottom of the argument block for this call.  We use indexing off there
        !          1964:    to store the arg.  On machines with push insns, ARGS_ADDR is 0 when a
        !          1965:    argument block has not been preallocated.
        !          1966: 
        !          1967:    ARGS_SO_FAR is the size of args previously pushed for this call.  */
        !          1968: 
        !          1969: void
        !          1970: emit_push_insn (x, mode, type, size, align, partial, reg, extra,
        !          1971:                args_addr, args_so_far)
        !          1972:      register rtx x;
        !          1973:      enum machine_mode mode;
        !          1974:      tree type;
        !          1975:      rtx size;
        !          1976:      int align;
        !          1977:      int partial;
        !          1978:      rtx reg;
        !          1979:      int extra;
        !          1980:      rtx args_addr;
        !          1981:      rtx args_so_far;
        !          1982: {
        !          1983:   rtx xinner;
        !          1984:   enum direction stack_direction
        !          1985: #ifdef STACK_GROWS_DOWNWARD
        !          1986:     = downward;
        !          1987: #else
        !          1988:     = upward;
        !          1989: #endif
        !          1990: 
        !          1991:   /* Decide where to pad the argument: `downward' for below,
        !          1992:      `upward' for above, or `none' for don't pad it.
        !          1993:      Default is below for small data on big-endian machines; else above.  */
        !          1994:   enum direction where_pad = FUNCTION_ARG_PADDING (mode, type);
        !          1995: 
        !          1996:   /* Invert direction if stack is post-update.  */
        !          1997:   if (STACK_PUSH_CODE == POST_INC || STACK_PUSH_CODE == POST_DEC)
        !          1998:     if (where_pad != none)
        !          1999:       where_pad = (where_pad == downward ? upward : downward);
        !          2000: 
        !          2001:   xinner = x = protect_from_queue (x, 0);
        !          2002: 
        !          2003:   if (mode == BLKmode)
        !          2004:     {
        !          2005:       /* Copy a block into the stack, entirely or partially.  */
        !          2006: 
        !          2007:       register rtx temp;
        !          2008:       int used = partial * UNITS_PER_WORD;
        !          2009:       int offset = used % (PARM_BOUNDARY / BITS_PER_UNIT);
        !          2010:       int skip;
        !          2011:       
        !          2012:       if (size == 0)
        !          2013:        abort ();
        !          2014: 
        !          2015:       used -= offset;
        !          2016: 
        !          2017:       /* USED is now the # of bytes we need not copy to the stack
        !          2018:         because registers will take care of them.  */
        !          2019: 
        !          2020:       if (partial != 0)
        !          2021:        xinner = change_address (xinner, BLKmode,
        !          2022:                                 plus_constant (XEXP (xinner, 0), used));
        !          2023: 
        !          2024:       /* If the partial register-part of the arg counts in its stack size,
        !          2025:         skip the part of stack space corresponding to the registers.
        !          2026:         Otherwise, start copying to the beginning of the stack space,
        !          2027:         by setting SKIP to 0.  */
        !          2028: #ifndef REG_PARM_STACK_SPACE
        !          2029:       skip = 0;
        !          2030: #else
        !          2031:       skip = used;
        !          2032: #endif
        !          2033: 
        !          2034: #ifdef PUSH_ROUNDING
        !          2035:       /* Do it with several push insns if that doesn't take lots of insns
        !          2036:         and if there is no difficulty with push insns that skip bytes
        !          2037:         on the stack for alignment purposes.  */
        !          2038:       if (args_addr == 0
        !          2039:          && GET_CODE (size) == CONST_INT
        !          2040:          && skip == 0
        !          2041:          && (move_by_pieces_ninsns ((unsigned) INTVAL (size) - used, align)
        !          2042:              < MOVE_RATIO)
        !          2043:          /* Here we avoid the case of a structure whose weak alignment
        !          2044:             forces many pushes of a small amount of data,
        !          2045:             and such small pushes do rounding that causes trouble.  */
        !          2046:          && ((! STRICT_ALIGNMENT && ! SLOW_UNALIGNED_ACCESS)
        !          2047:              || align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT
        !          2048:              || PUSH_ROUNDING (align) == align)
        !          2049:          && PUSH_ROUNDING (INTVAL (size)) == INTVAL (size))
        !          2050:        {
        !          2051:          /* Push padding now if padding above and stack grows down,
        !          2052:             or if padding below and stack grows up.
        !          2053:             But if space already allocated, this has already been done.  */
        !          2054:          if (extra && args_addr == 0
        !          2055:              && where_pad != none && where_pad != stack_direction)
        !          2056:            anti_adjust_stack (GEN_INT (extra));
        !          2057: 
        !          2058:          move_by_pieces (gen_rtx (MEM, BLKmode, gen_push_operand ()), xinner,
        !          2059:                          INTVAL (size) - used, align);
        !          2060:        }
        !          2061:       else
        !          2062: #endif /* PUSH_ROUNDING */
        !          2063:        {
        !          2064:          /* Otherwise make space on the stack and copy the data
        !          2065:             to the address of that space.  */
        !          2066: 
        !          2067:          /* Deduct words put into registers from the size we must copy.  */
        !          2068:          if (partial != 0)
        !          2069:            {
        !          2070:              if (GET_CODE (size) == CONST_INT)
        !          2071:                size = GEN_INT (INTVAL (size) - used);
        !          2072:              else
        !          2073:                size = expand_binop (GET_MODE (size), sub_optab, size,
        !          2074:                                     GEN_INT (used), NULL_RTX, 0,
        !          2075:                                     OPTAB_LIB_WIDEN);
        !          2076:            }
        !          2077: 
        !          2078:          /* Get the address of the stack space.
        !          2079:             In this case, we do not deal with EXTRA separately.
        !          2080:             A single stack adjust will do.  */
        !          2081:          if (! args_addr)
        !          2082:            {
        !          2083:              temp = push_block (size, extra, where_pad == downward);
        !          2084:              extra = 0;
        !          2085:            }
        !          2086:          else if (GET_CODE (args_so_far) == CONST_INT)
        !          2087:            temp = memory_address (BLKmode,
        !          2088:                                   plus_constant (args_addr,
        !          2089:                                                  skip + INTVAL (args_so_far)));
        !          2090:          else
        !          2091:            temp = memory_address (BLKmode,
        !          2092:                                   plus_constant (gen_rtx (PLUS, Pmode,
        !          2093:                                                           args_addr, args_so_far),
        !          2094:                                                  skip));
        !          2095: 
        !          2096:          /* TEMP is the address of the block.  Copy the data there.  */
        !          2097:          if (GET_CODE (size) == CONST_INT
        !          2098:              && (move_by_pieces_ninsns ((unsigned) INTVAL (size), align)
        !          2099:                  < MOVE_RATIO))
        !          2100:            {
        !          2101:              move_by_pieces (gen_rtx (MEM, BLKmode, temp), xinner,
        !          2102:                              INTVAL (size), align);
        !          2103:              goto ret;
        !          2104:            }
        !          2105:          /* Try the most limited insn first, because there's no point
        !          2106:             including more than one in the machine description unless
        !          2107:             the more limited one has some advantage.  */
        !          2108: #ifdef HAVE_movstrqi
        !          2109:          if (HAVE_movstrqi
        !          2110:              && GET_CODE (size) == CONST_INT
        !          2111:              && ((unsigned) INTVAL (size)
        !          2112:                  < (1 << (GET_MODE_BITSIZE (QImode) - 1))))
        !          2113:            {
        !          2114:              rtx pat = gen_movstrqi (gen_rtx (MEM, BLKmode, temp),
        !          2115:                                      xinner, size, GEN_INT (align));
        !          2116:              if (pat != 0)
        !          2117:                {
        !          2118:                  emit_insn (pat);
        !          2119:                  goto ret;
        !          2120:                }
        !          2121:            }
        !          2122: #endif
        !          2123: #ifdef HAVE_movstrhi
        !          2124:          if (HAVE_movstrhi
        !          2125:              && GET_CODE (size) == CONST_INT
        !          2126:              && ((unsigned) INTVAL (size)
        !          2127:                  < (1 << (GET_MODE_BITSIZE (HImode) - 1))))
        !          2128:            {
        !          2129:              rtx pat = gen_movstrhi (gen_rtx (MEM, BLKmode, temp),
        !          2130:                                      xinner, size, GEN_INT (align));
        !          2131:              if (pat != 0)
        !          2132:                {
        !          2133:                  emit_insn (pat);
        !          2134:                  goto ret;
        !          2135:                }
        !          2136:            }
        !          2137: #endif
        !          2138: #ifdef HAVE_movstrsi
        !          2139:          if (HAVE_movstrsi)
        !          2140:            {
        !          2141:              rtx pat = gen_movstrsi (gen_rtx (MEM, BLKmode, temp),
        !          2142:                                      xinner, size, GEN_INT (align));
        !          2143:              if (pat != 0)
        !          2144:                {
        !          2145:                  emit_insn (pat);
        !          2146:                  goto ret;
        !          2147:                }
        !          2148:            }
        !          2149: #endif
        !          2150: #ifdef HAVE_movstrdi
        !          2151:          if (HAVE_movstrdi)
        !          2152:            {
        !          2153:              rtx pat = gen_movstrdi (gen_rtx (MEM, BLKmode, temp),
        !          2154:                                      xinner, size, GEN_INT (align));
        !          2155:              if (pat != 0)
        !          2156:                {
        !          2157:                  emit_insn (pat);
        !          2158:                  goto ret;
        !          2159:                }
        !          2160:            }
        !          2161: #endif
        !          2162: 
        !          2163: #ifndef ACCUMULATE_OUTGOING_ARGS
        !          2164:          /* If the source is referenced relative to the stack pointer,
        !          2165:             copy it to another register to stabilize it.  We do not need
        !          2166:             to do this if we know that we won't be changing sp.  */
        !          2167: 
        !          2168:          if (reg_mentioned_p (virtual_stack_dynamic_rtx, temp)
        !          2169:              || reg_mentioned_p (virtual_outgoing_args_rtx, temp))
        !          2170:            temp = copy_to_reg (temp);
        !          2171: #endif
        !          2172: 
        !          2173:          /* Make inhibit_defer_pop nonzero around the library call
        !          2174:             to force it to pop the bcopy-arguments right away.  */
        !          2175:          NO_DEFER_POP;
        !          2176: #ifdef TARGET_MEM_FUNCTIONS
        !          2177:          emit_library_call (memcpy_libfunc, 0,
        !          2178:                             VOIDmode, 3, temp, Pmode, XEXP (xinner, 0), Pmode,
        !          2179:                             convert_to_mode (TYPE_MODE (sizetype),
        !          2180:                                              size, TREE_UNSIGNED (sizetype)),
        !          2181:                             TYPE_MODE (sizetype));
        !          2182: #else
        !          2183:          emit_library_call (bcopy_libfunc, 0,
        !          2184:                             VOIDmode, 3, XEXP (xinner, 0), Pmode, temp, Pmode,
        !          2185:                             convert_to_mode (TYPE_MODE (sizetype),
        !          2186:                                              size, TREE_UNSIGNED (sizetype)),
        !          2187:                             TYPE_MODE (sizetype));
        !          2188: #endif
        !          2189:          OK_DEFER_POP;
        !          2190:        }
        !          2191:     }
        !          2192:   else if (partial > 0)
        !          2193:     {
        !          2194:       /* Scalar partly in registers.  */
        !          2195: 
        !          2196:       int size = GET_MODE_SIZE (mode) / UNITS_PER_WORD;
        !          2197:       int i;
        !          2198:       int not_stack;
        !          2199:       /* # words of start of argument
        !          2200:         that we must make space for but need not store.  */
        !          2201:       int offset = partial % (PARM_BOUNDARY / BITS_PER_WORD);
        !          2202:       int args_offset = INTVAL (args_so_far);
        !          2203:       int skip;
        !          2204: 
        !          2205:       /* Push padding now if padding above and stack grows down,
        !          2206:         or if padding below and stack grows up.
        !          2207:         But if space already allocated, this has already been done.  */
        !          2208:       if (extra && args_addr == 0
        !          2209:          && where_pad != none && where_pad != stack_direction)
        !          2210:        anti_adjust_stack (GEN_INT (extra));
        !          2211: 
        !          2212:       /* If we make space by pushing it, we might as well push
        !          2213:         the real data.  Otherwise, we can leave OFFSET nonzero
        !          2214:         and leave the space uninitialized.  */
        !          2215:       if (args_addr == 0)
        !          2216:        offset = 0;
        !          2217: 
        !          2218:       /* Now NOT_STACK gets the number of words that we don't need to
        !          2219:         allocate on the stack.  */
        !          2220:       not_stack = partial - offset;
        !          2221: 
        !          2222:       /* If the partial register-part of the arg counts in its stack size,
        !          2223:         skip the part of stack space corresponding to the registers.
        !          2224:         Otherwise, start copying to the beginning of the stack space,
        !          2225:         by setting SKIP to 0.  */
        !          2226: #ifndef REG_PARM_STACK_SPACE
        !          2227:       skip = 0;
        !          2228: #else
        !          2229:       skip = not_stack;
        !          2230: #endif
        !          2231: 
        !          2232:       if (CONSTANT_P (x) && ! LEGITIMATE_CONSTANT_P (x))
        !          2233:        x = validize_mem (force_const_mem (mode, x));
        !          2234: 
        !          2235:       /* If X is a hard register in a non-integer mode, copy it into a pseudo;
        !          2236:         SUBREGs of such registers are not allowed.  */
        !          2237:       if ((GET_CODE (x) == REG && REGNO (x) < FIRST_PSEUDO_REGISTER
        !          2238:           && GET_MODE_CLASS (GET_MODE (x)) != MODE_INT))
        !          2239:        x = copy_to_reg (x);
        !          2240: 
        !          2241:       /* Loop over all the words allocated on the stack for this arg.  */
        !          2242:       /* We can do it by words, because any scalar bigger than a word
        !          2243:         has a size a multiple of a word.  */
        !          2244: #ifndef PUSH_ARGS_REVERSED
        !          2245:       for (i = not_stack; i < size; i++)
        !          2246: #else
        !          2247:       for (i = size - 1; i >= not_stack; i--)
        !          2248: #endif
        !          2249:        if (i >= not_stack + offset)
        !          2250:          emit_push_insn (operand_subword_force (x, i, mode),
        !          2251:                          word_mode, NULL_TREE, NULL_RTX, align, 0, NULL_RTX,
        !          2252:                          0, args_addr,
        !          2253:                          GEN_INT (args_offset + ((i - not_stack + skip)
        !          2254:                                                  * UNITS_PER_WORD)));
        !          2255:     }
        !          2256:   else
        !          2257:     {
        !          2258:       rtx addr;
        !          2259: 
        !          2260:       /* Push padding now if padding above and stack grows down,
        !          2261:         or if padding below and stack grows up.
        !          2262:         But if space already allocated, this has already been done.  */
        !          2263:       if (extra && args_addr == 0
        !          2264:          && where_pad != none && where_pad != stack_direction)
        !          2265:        anti_adjust_stack (GEN_INT (extra));
        !          2266: 
        !          2267: #ifdef PUSH_ROUNDING
        !          2268:       if (args_addr == 0)
        !          2269:        addr = gen_push_operand ();
        !          2270:       else
        !          2271: #endif
        !          2272:        if (GET_CODE (args_so_far) == CONST_INT)
        !          2273:          addr
        !          2274:            = memory_address (mode,
        !          2275:                              plus_constant (args_addr, INTVAL (args_so_far)));
        !          2276:       else
        !          2277:        addr = memory_address (mode, gen_rtx (PLUS, Pmode, args_addr,
        !          2278:                                              args_so_far));
        !          2279: 
        !          2280:       emit_move_insn (gen_rtx (MEM, mode, addr), x);
        !          2281:     }
        !          2282: 
        !          2283:  ret:
        !          2284:   /* If part should go in registers, copy that part
        !          2285:      into the appropriate registers.  Do this now, at the end,
        !          2286:      since mem-to-mem copies above may do function calls.  */
        !          2287:   if (partial > 0 && reg != 0)
        !          2288:     move_block_to_reg (REGNO (reg), x, partial, mode);
        !          2289: 
        !          2290:   if (extra && args_addr == 0 && where_pad == stack_direction)
        !          2291:     anti_adjust_stack (GEN_INT (extra));
        !          2292: }
        !          2293: 
        !          2294: /* Expand an assignment that stores the value of FROM into TO.
        !          2295:    If WANT_VALUE is nonzero, return an rtx for the value of TO.
        !          2296:    (This may contain a QUEUED rtx;
        !          2297:    if the value is constant, this rtx is a constant.)
        !          2298:    Otherwise, the returned value is NULL_RTX.
        !          2299: 
        !          2300:    SUGGEST_REG is no longer actually used.
        !          2301:    It used to mean, copy the value through a register
        !          2302:    and return that register, if that is possible.
        !          2303:    We now use WANT_VALUE to decide whether to do this.  */
        !          2304: 
        !          2305: rtx
        !          2306: expand_assignment (to, from, want_value, suggest_reg)
        !          2307:      tree to, from;
        !          2308:      int want_value;
        !          2309:      int suggest_reg;
        !          2310: {
        !          2311:   register rtx to_rtx = 0;
        !          2312:   rtx result;
        !          2313: 
        !          2314:   /* Don't crash if the lhs of the assignment was erroneous.  */
        !          2315: 
        !          2316:   if (TREE_CODE (to) == ERROR_MARK)
        !          2317:     {
        !          2318:       result = expand_expr (from, NULL_RTX, VOIDmode, 0);
        !          2319:       return want_value ? result : NULL_RTX;
        !          2320:     }
        !          2321: 
        !          2322:   if (output_bytecode)
        !          2323:     {
        !          2324:       tree dest_innermost;
        !          2325: 
        !          2326:       bc_expand_expr (from);
        !          2327:       bc_emit_instruction (duplicate);
        !          2328: 
        !          2329:       dest_innermost = bc_expand_address (to);
        !          2330: 
        !          2331:       /* Can't deduce from TYPE that we're dealing with a bitfield, so
        !          2332:         take care of it here. */
        !          2333: 
        !          2334:       bc_store_memory (TREE_TYPE (to), dest_innermost);
        !          2335:       return NULL;
        !          2336:     }
        !          2337: 
        !          2338:   /* Assignment of a structure component needs special treatment
        !          2339:      if the structure component's rtx is not simply a MEM.
        !          2340:      Assignment of an array element at a constant index
        !          2341:      has the same problem.  */
        !          2342: 
        !          2343:   if (TREE_CODE (to) == COMPONENT_REF
        !          2344:       || TREE_CODE (to) == BIT_FIELD_REF
        !          2345:       || (TREE_CODE (to) == ARRAY_REF
        !          2346:          && TREE_CODE (TREE_OPERAND (to, 1)) == INTEGER_CST
        !          2347:          && TREE_CODE (TYPE_SIZE (TREE_TYPE (to))) == INTEGER_CST))
        !          2348:     {
        !          2349:       enum machine_mode mode1;
        !          2350:       int bitsize;
        !          2351:       int bitpos;
        !          2352:       tree offset;
        !          2353:       int unsignedp;
        !          2354:       int volatilep = 0;
        !          2355:       tree tem;
        !          2356:       int alignment;
        !          2357: 
        !          2358:       push_temp_slots ();
        !          2359:       tem = get_inner_reference (to, &bitsize, &bitpos, &offset,
        !          2360:                                      &mode1, &unsignedp, &volatilep);
        !          2361: 
        !          2362:       /* If we are going to use store_bit_field and extract_bit_field,
        !          2363:         make sure to_rtx will be safe for multiple use.  */
        !          2364: 
        !          2365:       if (mode1 == VOIDmode && want_value)
        !          2366:        tem = stabilize_reference (tem);
        !          2367: 
        !          2368:       alignment = TYPE_ALIGN (TREE_TYPE (tem)) / BITS_PER_UNIT;
        !          2369:       to_rtx = expand_expr (tem, NULL_RTX, VOIDmode, 0);
        !          2370:       if (offset != 0)
        !          2371:        {
        !          2372:          rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
        !          2373: 
        !          2374:          if (GET_CODE (to_rtx) != MEM)
        !          2375:            abort ();
        !          2376:          to_rtx = change_address (to_rtx, VOIDmode,
        !          2377:                                   gen_rtx (PLUS, Pmode, XEXP (to_rtx, 0),
        !          2378:                                            force_reg (Pmode, offset_rtx)));
        !          2379:          /* If we have a variable offset, the known alignment
        !          2380:             is only that of the innermost structure containing the field.
        !          2381:             (Actually, we could sometimes do better by using the
        !          2382:             align of an element of the innermost array, but no need.)  */
        !          2383:          if (TREE_CODE (to) == COMPONENT_REF
        !          2384:              || TREE_CODE (to) == BIT_FIELD_REF)
        !          2385:            alignment
        !          2386:              = TYPE_ALIGN (TREE_TYPE (TREE_OPERAND (to, 0))) / BITS_PER_UNIT;
        !          2387:        }
        !          2388:       if (volatilep)
        !          2389:        {
        !          2390:          if (GET_CODE (to_rtx) == MEM)
        !          2391:            MEM_VOLATILE_P (to_rtx) = 1;
        !          2392: #if 0  /* This was turned off because, when a field is volatile
        !          2393:          in an object which is not volatile, the object may be in a register,
        !          2394:          and then we would abort over here.  */
        !          2395:          else
        !          2396:            abort ();
        !          2397: #endif
        !          2398:        }
        !          2399: 
        !          2400: 
        !          2401:       /*
        !          2402:       if (TREE_SELF_OFFSET (TREE_OPERAND (to, 1)))
        !          2403:        {
        !          2404:          from = build_binary_op (MINUS_EXPR, from,
        !          2405:                                  build1 (ADDR_EXPR, TREE_TYPE (to), to));
        !          2406:        }
        !          2407: */
        !          2408: 
        !          2409:       result = store_field (to_rtx, bitsize, bitpos, mode1, from,
        !          2410:                            (want_value
        !          2411:                             /* Spurious cast makes HPUX compiler happy.  */
        !          2412:                             ? (enum machine_mode) TYPE_MODE (TREE_TYPE (to))
        !          2413:                             : VOIDmode),
        !          2414:                            unsignedp,
        !          2415:                            /* Required alignment of containing datum.  */
        !          2416:                            alignment,
        !          2417:                            int_size_in_bytes (TREE_TYPE (tem)));
        !          2418:       preserve_temp_slots (result);
        !          2419:       free_temp_slots ();
        !          2420:       pop_temp_slots ();
        !          2421: 
        !          2422:       /* If the value is meaningful, convert RESULT to the proper mode.
        !          2423:         Otherwise, return nothing.  */
        !          2424:       return (want_value ? convert_modes (TYPE_MODE (TREE_TYPE (to)),
        !          2425:                                          TYPE_MODE (TREE_TYPE (from)),
        !          2426:                                          result,
        !          2427:                                          TREE_UNSIGNED (TREE_TYPE (to)))
        !          2428:              : NULL_RTX);
        !          2429:     }
        !          2430: 
        !          2431:   /* If the rhs is a function call and its value is not an aggregate,
        !          2432:      call the function before we start to compute the lhs.
        !          2433:      This is needed for correct code for cases such as
        !          2434:      val = setjmp (buf) on machines where reference to val
        !          2435:      requires loading up part of an address in a separate insn.
        !          2436: 
        !          2437:      Don't do this if TO is a VAR_DECL whose DECL_RTL is REG since it might be
        !          2438:      a promoted variable where the zero- or sign- extension needs to be done.
        !          2439:      Handling this in the normal way is safe because no computation is done
        !          2440:      before the call.  */
        !          2441:   if (TREE_CODE (from) == CALL_EXPR && ! aggregate_value_p (from)
        !          2442:       && ! (TREE_CODE (to) == VAR_DECL && GET_CODE (DECL_RTL (to)) == REG))
        !          2443:     {
        !          2444:       rtx value;
        !          2445: 
        !          2446:       push_temp_slots ();
        !          2447:       value = expand_expr (from, NULL_RTX, VOIDmode, 0);
        !          2448:       if (to_rtx == 0)
        !          2449:        to_rtx = expand_expr (to, NULL_RTX, VOIDmode, EXPAND_CONST_ADDRESS);
        !          2450: 
        !          2451:       emit_move_insn (to_rtx, value);
        !          2452:       preserve_temp_slots (to_rtx);
        !          2453:       free_temp_slots ();
        !          2454:       pop_temp_slots ();
        !          2455:       return want_value ? to_rtx : NULL_RTX;
        !          2456:     }
        !          2457: 
        !          2458:   /* Ordinary treatment.  Expand TO to get a REG or MEM rtx.
        !          2459:      Don't re-expand if it was expanded already (in COMPONENT_REF case).  */
        !          2460: 
        !          2461:   if (to_rtx == 0)
        !          2462:     to_rtx = expand_expr (to, NULL_RTX, VOIDmode, EXPAND_CONST_ADDRESS);
        !          2463: 
        !          2464:   /*
        !          2465:   if (TREE_SELF_OFFSET (to))
        !          2466:     {
        !          2467:       from = build_binary_op (MINUS_EXPR, from,
        !          2468:                              build1 (ADDR_EXPR, TREE_TYPE (to), to));
        !          2469:     }
        !          2470:     */
        !          2471: 
        !          2472:   /* Don't move directly into a return register.  */
        !          2473:   if (TREE_CODE (to) == RESULT_DECL && GET_CODE (to_rtx) == REG)
        !          2474:     {
        !          2475:       rtx temp;
        !          2476: 
        !          2477:       push_temp_slots ();
        !          2478:       temp = expand_expr (from, 0, GET_MODE (to_rtx), 0);
        !          2479:       emit_move_insn (to_rtx, temp);
        !          2480:       preserve_temp_slots (to_rtx);
        !          2481:       free_temp_slots ();
        !          2482:       pop_temp_slots ();
        !          2483:       return want_value ? to_rtx : NULL_RTX;
        !          2484:     }
        !          2485: 
        !          2486:   /* In case we are returning the contents of an object which overlaps
        !          2487:      the place the value is being stored, use a safe function when copying
        !          2488:      a value through a pointer into a structure value return block.  */
        !          2489:   if (TREE_CODE (to) == RESULT_DECL && TREE_CODE (from) == INDIRECT_REF
        !          2490:       && current_function_returns_struct
        !          2491:       && !current_function_returns_pcc_struct)
        !          2492:     {
        !          2493:       rtx from_rtx, size;
        !          2494: 
        !          2495:       push_temp_slots ();
        !          2496:       size = expr_size (from);
        !          2497:       from_rtx = expand_expr (from, NULL_RTX, VOIDmode, 0);
        !          2498: 
        !          2499: #ifdef TARGET_MEM_FUNCTIONS
        !          2500:       emit_library_call (memcpy_libfunc, 0,
        !          2501:                         VOIDmode, 3, XEXP (to_rtx, 0), Pmode,
        !          2502:                         XEXP (from_rtx, 0), Pmode,
        !          2503:                         convert_to_mode (TYPE_MODE (sizetype),
        !          2504:                                          size, TREE_UNSIGNED (sizetype)),
        !          2505:                         TYPE_MODE (sizetype));
        !          2506: #else
        !          2507:       emit_library_call (bcopy_libfunc, 0,
        !          2508:                         VOIDmode, 3, XEXP (from_rtx, 0), Pmode,
        !          2509:                         XEXP (to_rtx, 0), Pmode,
        !          2510:                         convert_to_mode (TYPE_MODE (sizetype),
        !          2511:                                          size, TREE_UNSIGNED (sizetype)),
        !          2512:                         TYPE_MODE (sizetype));
        !          2513: #endif
        !          2514: 
        !          2515:       preserve_temp_slots (to_rtx);
        !          2516:       free_temp_slots ();
        !          2517:       pop_temp_slots ();
        !          2518:       return want_value ? to_rtx : NULL_RTX;
        !          2519:     }
        !          2520: 
        !          2521:   /* Compute FROM and store the value in the rtx we got.  */
        !          2522: 
        !          2523:   push_temp_slots ();
        !          2524:   result = store_expr (from, to_rtx, want_value);
        !          2525:   preserve_temp_slots (result);
        !          2526:   free_temp_slots ();
        !          2527:   pop_temp_slots ();
        !          2528:   return want_value ? result : NULL_RTX;
        !          2529: }
        !          2530: 
        !          2531: /* Generate code for computing expression EXP,
        !          2532:    and storing the value into TARGET.
        !          2533:    TARGET may contain a QUEUED rtx.
        !          2534: 
        !          2535:    If WANT_VALUE is nonzero, return a copy of the value
        !          2536:    not in TARGET, so that we can be sure to use the proper
        !          2537:    value in a containing expression even if TARGET has something
        !          2538:    else stored in it.  If possible, we copy the value through a pseudo
        !          2539:    and return that pseudo.  Or, if the value is constant, we try to
        !          2540:    return the constant.  In some cases, we return a pseudo
        !          2541:    copied *from* TARGET.
        !          2542: 
        !          2543:    If the mode is BLKmode then we may return TARGET itself.
        !          2544:    It turns out that in BLKmode it doesn't cause a problem.
        !          2545:    because C has no operators that could combine two different
        !          2546:    assignments into the same BLKmode object with different values
        !          2547:    with no sequence point.  Will other languages need this to
        !          2548:    be more thorough?
        !          2549: 
        !          2550:    If WANT_VALUE is 0, we return NULL, to make sure
        !          2551:    to catch quickly any cases where the caller uses the value
        !          2552:    and fails to set WANT_VALUE.  */
        !          2553: 
        !          2554: rtx
        !          2555: store_expr (exp, target, want_value)
        !          2556:      register tree exp;
        !          2557:      register rtx target;
        !          2558:      int want_value;
        !          2559: {
        !          2560:   register rtx temp;
        !          2561:   int dont_return_target = 0;
        !          2562: 
        !          2563:   if (TREE_CODE (exp) == COMPOUND_EXPR)
        !          2564:     {
        !          2565:       /* Perform first part of compound expression, then assign from second
        !          2566:         part.  */
        !          2567:       expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0);
        !          2568:       emit_queue ();
        !          2569:       return store_expr (TREE_OPERAND (exp, 1), target, want_value);
        !          2570:     }
        !          2571:   else if (TREE_CODE (exp) == COND_EXPR && GET_MODE (target) == BLKmode)
        !          2572:     {
        !          2573:       /* For conditional expression, get safe form of the target.  Then
        !          2574:         test the condition, doing the appropriate assignment on either
        !          2575:         side.  This avoids the creation of unnecessary temporaries.
        !          2576:         For non-BLKmode, it is more efficient not to do this.  */
        !          2577: 
        !          2578:       rtx lab1 = gen_label_rtx (), lab2 = gen_label_rtx ();
        !          2579: 
        !          2580:       emit_queue ();
        !          2581:       target = protect_from_queue (target, 1);
        !          2582: 
        !          2583:       NO_DEFER_POP;
        !          2584:       jumpifnot (TREE_OPERAND (exp, 0), lab1);
        !          2585:       store_expr (TREE_OPERAND (exp, 1), target, 0);
        !          2586:       emit_queue ();
        !          2587:       emit_jump_insn (gen_jump (lab2));
        !          2588:       emit_barrier ();
        !          2589:       emit_label (lab1);
        !          2590:       store_expr (TREE_OPERAND (exp, 2), target, 0);
        !          2591:       emit_queue ();
        !          2592:       emit_label (lab2);
        !          2593:       OK_DEFER_POP;
        !          2594:       return want_value ? target : NULL_RTX;
        !          2595:     }
        !          2596:   else if (want_value && GET_CODE (target) == MEM && ! MEM_VOLATILE_P (target)
        !          2597:           && GET_MODE (target) != BLKmode)
        !          2598:     /* If target is in memory and caller wants value in a register instead,
        !          2599:        arrange that.  Pass TARGET as target for expand_expr so that,
        !          2600:        if EXP is another assignment, WANT_VALUE will be nonzero for it.
        !          2601:        We know expand_expr will not use the target in that case.
        !          2602:        Don't do this if TARGET is volatile because we are supposed
        !          2603:        to write it and then read it.  */
        !          2604:     {
        !          2605:       temp = expand_expr (exp, cse_not_expected ? NULL_RTX : target,
        !          2606:                          GET_MODE (target), 0);
        !          2607:       if (GET_MODE (temp) != BLKmode && GET_MODE (temp) != VOIDmode)
        !          2608:        temp = copy_to_reg (temp);
        !          2609:       dont_return_target = 1;
        !          2610:     }
        !          2611:   else if (queued_subexp_p (target))
        !          2612:     /* If target contains a postincrement, let's not risk
        !          2613:        using it as the place to generate the rhs.  */
        !          2614:     {
        !          2615:       if (GET_MODE (target) != BLKmode && GET_MODE (target) != VOIDmode)
        !          2616:        {
        !          2617:          /* Expand EXP into a new pseudo.  */
        !          2618:          temp = gen_reg_rtx (GET_MODE (target));
        !          2619:          temp = expand_expr (exp, temp, GET_MODE (target), 0);
        !          2620:        }
        !          2621:       else
        !          2622:        temp = expand_expr (exp, NULL_RTX, GET_MODE (target), 0);
        !          2623: 
        !          2624:       /* If target is volatile, ANSI requires accessing the value
        !          2625:         *from* the target, if it is accessed.  So make that happen.
        !          2626:         In no case return the target itself.  */
        !          2627:       if (! MEM_VOLATILE_P (target) && want_value)
        !          2628:        dont_return_target = 1;
        !          2629:     }
        !          2630:   else if (GET_CODE (target) == SUBREG && SUBREG_PROMOTED_VAR_P (target))
        !          2631:     /* If this is an scalar in a register that is stored in a wider mode
        !          2632:        than the declared mode, compute the result into its declared mode
        !          2633:        and then convert to the wider mode.  Our value is the computed
        !          2634:        expression.  */
        !          2635:     {
        !          2636:       temp = expand_expr (exp, NULL_RTX, VOIDmode, 0);
        !          2637: 
        !          2638:       /* If TEMP is a VOIDmode constant, use convert_modes to make
        !          2639:         sure that we properly convert it.  */
        !          2640:       if (CONSTANT_P (temp) && GET_MODE (temp) == VOIDmode)
        !          2641:        temp = convert_modes (GET_MODE (SUBREG_REG (target)),
        !          2642:                              TYPE_MODE (TREE_TYPE (exp)), temp,
        !          2643:                              SUBREG_PROMOTED_UNSIGNED_P (target));
        !          2644: 
        !          2645:       convert_move (SUBREG_REG (target), temp,
        !          2646:                    SUBREG_PROMOTED_UNSIGNED_P (target));
        !          2647:       return want_value ? temp : NULL_RTX;
        !          2648:     }
        !          2649:   else
        !          2650:     {
        !          2651:       temp = expand_expr (exp, target, GET_MODE (target), 0);
        !          2652:       /* DO return TARGET if it's a specified hardware register.
        !          2653:         expand_return relies on this.
        !          2654:         If TARGET is a volatile mem ref, either return TARGET
        !          2655:         or return a reg copied *from* TARGET; ANSI requires this.
        !          2656: 
        !          2657:         Otherwise, if TEMP is not TARGET, return TEMP
        !          2658:         if it is constant (for efficiency),
        !          2659:         or if we really want the correct value.  */
        !          2660:       if (!(target && GET_CODE (target) == REG
        !          2661:            && REGNO (target) < FIRST_PSEUDO_REGISTER)
        !          2662:          && !(GET_CODE (target) == MEM && MEM_VOLATILE_P (target))
        !          2663:          && temp != target
        !          2664:          && (CONSTANT_P (temp) || want_value))
        !          2665:        dont_return_target = 1;
        !          2666:     }
        !          2667: 
        !          2668:   /* If TEMP is a VOIDmode constant and the mode of the type of EXP is not
        !          2669:      the same as that of TARGET, adjust the constant.  This is needed, for
        !          2670:      example, in case it is a CONST_DOUBLE and we want only a word-sized
        !          2671:      value.  */
        !          2672:   if (CONSTANT_P (temp) && GET_MODE (temp) == VOIDmode
        !          2673:       && GET_MODE (target) != TYPE_MODE (TREE_TYPE (exp)))
        !          2674:     temp = convert_modes (GET_MODE (target), TYPE_MODE (TREE_TYPE (exp)),
        !          2675:                          temp, TREE_UNSIGNED (TREE_TYPE (exp)));
        !          2676: 
        !          2677:   /* If value was not generated in the target, store it there.
        !          2678:      Convert the value to TARGET's type first if nec.  */
        !          2679: 
        !          2680:   if (temp != target && TREE_CODE (exp) != ERROR_MARK)
        !          2681:     {
        !          2682:       target = protect_from_queue (target, 1);
        !          2683:       if (GET_MODE (temp) != GET_MODE (target)
        !          2684:          && GET_MODE (temp) != VOIDmode)
        !          2685:        {
        !          2686:          int unsignedp = TREE_UNSIGNED (TREE_TYPE (exp));
        !          2687:          if (dont_return_target)
        !          2688:            {
        !          2689:              /* In this case, we will return TEMP,
        !          2690:                 so make sure it has the proper mode.
        !          2691:                 But don't forget to store the value into TARGET.  */
        !          2692:              temp = convert_to_mode (GET_MODE (target), temp, unsignedp);
        !          2693:              emit_move_insn (target, temp);
        !          2694:            }
        !          2695:          else
        !          2696:            convert_move (target, temp, unsignedp);
        !          2697:        }
        !          2698: 
        !          2699:       else if (GET_MODE (temp) == BLKmode && TREE_CODE (exp) == STRING_CST)
        !          2700:        {
        !          2701:          /* Handle copying a string constant into an array.
        !          2702:             The string constant may be shorter than the array.
        !          2703:             So copy just the string's actual length, and clear the rest.  */
        !          2704:          rtx size;
        !          2705: 
        !          2706:          /* Get the size of the data type of the string,
        !          2707:             which is actually the size of the target.  */
        !          2708:          size = expr_size (exp);
        !          2709:          if (GET_CODE (size) == CONST_INT
        !          2710:              && INTVAL (size) < TREE_STRING_LENGTH (exp))
        !          2711:            emit_block_move (target, temp, size,
        !          2712:                             TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
        !          2713:          else
        !          2714:            {
        !          2715:              /* Compute the size of the data to copy from the string.  */
        !          2716:              tree copy_size
        !          2717:                = size_binop (MIN_EXPR,
        !          2718:                              make_tree (sizetype, size),
        !          2719:                              convert (sizetype,
        !          2720:                                       build_int_2 (TREE_STRING_LENGTH (exp), 0)));
        !          2721:              rtx copy_size_rtx = expand_expr (copy_size, NULL_RTX,
        !          2722:                                               VOIDmode, 0);
        !          2723:              rtx label = 0;
        !          2724: 
        !          2725:              /* Copy that much.  */
        !          2726:              emit_block_move (target, temp, copy_size_rtx,
        !          2727:                               TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
        !          2728: 
        !          2729:              /* Figure out how much is left in TARGET
        !          2730:                 that we have to clear.  */
        !          2731:              if (GET_CODE (copy_size_rtx) == CONST_INT)
        !          2732:                {
        !          2733:                  temp = plus_constant (XEXP (target, 0),
        !          2734:                                        TREE_STRING_LENGTH (exp));
        !          2735:                  size = plus_constant (size,
        !          2736:                                        - TREE_STRING_LENGTH (exp));
        !          2737:                }
        !          2738:              else
        !          2739:                {
        !          2740:                  enum machine_mode size_mode = Pmode;
        !          2741: 
        !          2742:                  temp = force_reg (Pmode, XEXP (target, 0));
        !          2743:                  temp = expand_binop (size_mode, add_optab, temp,
        !          2744:                                       copy_size_rtx, NULL_RTX, 0,
        !          2745:                                       OPTAB_LIB_WIDEN);
        !          2746: 
        !          2747:                  size = expand_binop (size_mode, sub_optab, size,
        !          2748:                                       copy_size_rtx, NULL_RTX, 0,
        !          2749:                                       OPTAB_LIB_WIDEN);
        !          2750: 
        !          2751:                  emit_cmp_insn (size, const0_rtx, LT, NULL_RTX,
        !          2752:                                 GET_MODE (size), 0, 0);
        !          2753:                  label = gen_label_rtx ();
        !          2754:                  emit_jump_insn (gen_blt (label));
        !          2755:                }
        !          2756: 
        !          2757:              if (size != const0_rtx)
        !          2758:                {
        !          2759: #ifdef TARGET_MEM_FUNCTIONS
        !          2760:                  emit_library_call (memset_libfunc, 0, VOIDmode, 3,
        !          2761:                                     temp, Pmode, const0_rtx, Pmode, size, Pmode);
        !          2762: #else
        !          2763:                  emit_library_call (bzero_libfunc, 0, VOIDmode, 2,
        !          2764:                                     temp, Pmode, size, Pmode);
        !          2765: #endif
        !          2766:                }
        !          2767:              if (label)
        !          2768:                emit_label (label);
        !          2769:            }
        !          2770:        }
        !          2771:       else if (GET_MODE (temp) == BLKmode)
        !          2772:        emit_block_move (target, temp, expr_size (exp),
        !          2773:                         TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
        !          2774:       else
        !          2775:        emit_move_insn (target, temp);
        !          2776:     }
        !          2777: 
        !          2778:   if (dont_return_target && GET_CODE (temp) != MEM)
        !          2779:     return temp;
        !          2780:   if (want_value && GET_MODE (target) != BLKmode)
        !          2781:     return copy_to_reg (target);
        !          2782:   if (want_value)
        !          2783:     return target;
        !          2784:   return NULL_RTX;
        !          2785: }
        !          2786: 
        !          2787: /* Store the value of constructor EXP into the rtx TARGET.
        !          2788:    TARGET is either a REG or a MEM.  */
        !          2789: 
        !          2790: static void
        !          2791: store_constructor (exp, target)
        !          2792:      tree exp;
        !          2793:      rtx target;
        !          2794: {
        !          2795:   tree type = TREE_TYPE (exp);
        !          2796: 
        !          2797:   /* We know our target cannot conflict, since safe_from_p has been called.  */
        !          2798: #if 0
        !          2799:   /* Don't try copying piece by piece into a hard register
        !          2800:      since that is vulnerable to being clobbered by EXP.
        !          2801:      Instead, construct in a pseudo register and then copy it all.  */
        !          2802:   if (GET_CODE (target) == REG && REGNO (target) < FIRST_PSEUDO_REGISTER)
        !          2803:     {
        !          2804:       rtx temp = gen_reg_rtx (GET_MODE (target));
        !          2805:       store_constructor (exp, temp);
        !          2806:       emit_move_insn (target, temp);
        !          2807:       return;
        !          2808:     }
        !          2809: #endif
        !          2810: 
        !          2811:   if (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE
        !          2812:       || TREE_CODE (type) == QUAL_UNION_TYPE)
        !          2813:     {
        !          2814:       register tree elt;
        !          2815: 
        !          2816:       /* Inform later passes that the whole union value is dead.  */
        !          2817:       if (TREE_CODE (type) == UNION_TYPE
        !          2818:          || TREE_CODE (type) == QUAL_UNION_TYPE)
        !          2819:        emit_insn (gen_rtx (CLOBBER, VOIDmode, target));
        !          2820: 
        !          2821:       /* If we are building a static constructor into a register,
        !          2822:         set the initial value as zero so we can fold the value into
        !          2823:         a constant.  */
        !          2824:       else if (GET_CODE (target) == REG && TREE_STATIC (exp))
        !          2825:        emit_move_insn (target, const0_rtx);
        !          2826: 
        !          2827:       /* If the constructor has fewer fields than the structure,
        !          2828:         clear the whole structure first.  */
        !          2829:       else if (list_length (CONSTRUCTOR_ELTS (exp))
        !          2830:               != list_length (TYPE_FIELDS (type)))
        !          2831:        clear_storage (target, int_size_in_bytes (type));
        !          2832:       else
        !          2833:        /* Inform later passes that the old value is dead.  */
        !          2834:        emit_insn (gen_rtx (CLOBBER, VOIDmode, target));
        !          2835: 
        !          2836:       /* Store each element of the constructor into
        !          2837:         the corresponding field of TARGET.  */
        !          2838: 
        !          2839:       for (elt = CONSTRUCTOR_ELTS (exp); elt; elt = TREE_CHAIN (elt))
        !          2840:        {
        !          2841:          register tree field = TREE_PURPOSE (elt);
        !          2842:          register enum machine_mode mode;
        !          2843:          int bitsize;
        !          2844:          int bitpos = 0;
        !          2845:          int unsignedp;
        !          2846:          tree pos, constant = 0, offset = 0;
        !          2847:          rtx to_rtx = target;
        !          2848: 
        !          2849:          /* Just ignore missing fields.
        !          2850:             We cleared the whole structure, above,
        !          2851:             if any fields are missing.  */
        !          2852:          if (field == 0)
        !          2853:            continue;
        !          2854: 
        !          2855:          bitsize = TREE_INT_CST_LOW (DECL_SIZE (field));
        !          2856:          unsignedp = TREE_UNSIGNED (field);
        !          2857:          mode = DECL_MODE (field);
        !          2858:          if (DECL_BIT_FIELD (field))
        !          2859:            mode = VOIDmode;
        !          2860: 
        !          2861:          pos = DECL_FIELD_BITPOS (field);
        !          2862:          if (TREE_CODE (pos) == INTEGER_CST)
        !          2863:            constant = pos;
        !          2864:          else if (TREE_CODE (pos) == PLUS_EXPR
        !          2865:                   && TREE_CODE (TREE_OPERAND (pos, 1)) == INTEGER_CST)
        !          2866:            constant = TREE_OPERAND (pos, 1), offset = TREE_OPERAND (pos, 0);
        !          2867:          else
        !          2868:            offset = pos;
        !          2869: 
        !          2870:          if (constant)
        !          2871:            bitpos = TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field));
        !          2872: 
        !          2873:          if (offset)
        !          2874:            {
        !          2875:              rtx offset_rtx;
        !          2876: 
        !          2877:              if (contains_placeholder_p (offset))
        !          2878:                offset = build (WITH_RECORD_EXPR, sizetype,
        !          2879:                                offset, exp);
        !          2880: 
        !          2881:              offset = size_binop (FLOOR_DIV_EXPR, offset,
        !          2882:                                   size_int (BITS_PER_UNIT));
        !          2883: 
        !          2884:              offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
        !          2885:              if (GET_CODE (to_rtx) != MEM)
        !          2886:                abort ();
        !          2887: 
        !          2888:              to_rtx
        !          2889:                = change_address (to_rtx, VOIDmode,
        !          2890:                                  gen_rtx (PLUS, Pmode, XEXP (to_rtx, 0),
        !          2891:                                           force_reg (Pmode, offset_rtx)));
        !          2892:            }
        !          2893: 
        !          2894:          store_field (to_rtx, bitsize, bitpos, mode, TREE_VALUE (elt),
        !          2895:                       /* The alignment of TARGET is
        !          2896:                          at least what its type requires.  */
        !          2897:                       VOIDmode, 0,
        !          2898:                       TYPE_ALIGN (type) / BITS_PER_UNIT,
        !          2899:                       int_size_in_bytes (type));
        !          2900:        }
        !          2901:     }
        !          2902:   else if (TREE_CODE (type) == ARRAY_TYPE)
        !          2903:     {
        !          2904:       register tree elt;
        !          2905:       register int i;
        !          2906:       tree domain = TYPE_DOMAIN (type);
        !          2907:       HOST_WIDE_INT minelt = TREE_INT_CST_LOW (TYPE_MIN_VALUE (domain));
        !          2908:       HOST_WIDE_INT maxelt = TREE_INT_CST_LOW (TYPE_MAX_VALUE (domain));
        !          2909:       tree elttype = TREE_TYPE (type);
        !          2910: 
        !          2911:       /* If the constructor has fewer fields than the structure,
        !          2912:         clear the whole structure first.  Similarly if this this is
        !          2913:         static constructor of a non-BLKmode object.  */
        !          2914: 
        !          2915:       if (list_length (CONSTRUCTOR_ELTS (exp)) < maxelt - minelt + 1
        !          2916:          || (GET_CODE (target) == REG && TREE_STATIC (exp)))
        !          2917:        clear_storage (target, int_size_in_bytes (type));
        !          2918:       else
        !          2919:        /* Inform later passes that the old value is dead.  */
        !          2920:        emit_insn (gen_rtx (CLOBBER, VOIDmode, target));
        !          2921: 
        !          2922:       /* Store each element of the constructor into
        !          2923:         the corresponding element of TARGET, determined
        !          2924:         by counting the elements.  */
        !          2925:       for (elt = CONSTRUCTOR_ELTS (exp), i = 0;
        !          2926:           elt;
        !          2927:           elt = TREE_CHAIN (elt), i++)
        !          2928:        {
        !          2929:          register enum machine_mode mode;
        !          2930:          int bitsize;
        !          2931:          int bitpos;
        !          2932:          int unsignedp;
        !          2933:          tree index = TREE_PURPOSE (elt);
        !          2934:          rtx xtarget = target;
        !          2935: 
        !          2936:          mode = TYPE_MODE (elttype);
        !          2937:          bitsize = GET_MODE_BITSIZE (mode);
        !          2938:          unsignedp = TREE_UNSIGNED (elttype);
        !          2939: 
        !          2940:          if (index != 0 && TREE_CODE (index) != INTEGER_CST)
        !          2941:            {
        !          2942:              /* We don't currently allow variable indices in a
        !          2943:                 C initializer, but let's try here to support them.  */
        !          2944:              rtx pos_rtx, addr, xtarget;
        !          2945:              tree position;
        !          2946: 
        !          2947:              position = size_binop (MULT_EXPR, index, TYPE_SIZE (elttype));
        !          2948:              pos_rtx = expand_expr (position, 0, VOIDmode, 0);
        !          2949:              addr = gen_rtx (PLUS, Pmode, XEXP (target, 0), pos_rtx);
        !          2950:              xtarget = change_address (target, mode, addr);
        !          2951:              store_expr (TREE_VALUE (elt), xtarget, 0);
        !          2952:            }
        !          2953:          else
        !          2954:            {
        !          2955:              if (index != 0)
        !          2956:                bitpos = ((TREE_INT_CST_LOW (index) - minelt)
        !          2957:                          * TREE_INT_CST_LOW (TYPE_SIZE (elttype)));
        !          2958:              else
        !          2959:                bitpos = (i * TREE_INT_CST_LOW (TYPE_SIZE (elttype)));
        !          2960: 
        !          2961:              store_field (xtarget, bitsize, bitpos, mode, TREE_VALUE (elt),
        !          2962:                           /* The alignment of TARGET is
        !          2963:                              at least what its type requires.  */
        !          2964:                           VOIDmode, 0,
        !          2965:                           TYPE_ALIGN (type) / BITS_PER_UNIT,
        !          2966:                           int_size_in_bytes (type));
        !          2967:            }
        !          2968:        }
        !          2969:     }
        !          2970: 
        !          2971:   else
        !          2972:     abort ();
        !          2973: }
        !          2974: 
        !          2975: /* Store the value of EXP (an expression tree)
        !          2976:    into a subfield of TARGET which has mode MODE and occupies
        !          2977:    BITSIZE bits, starting BITPOS bits from the start of TARGET.
        !          2978:    If MODE is VOIDmode, it means that we are storing into a bit-field.
        !          2979: 
        !          2980:    If VALUE_MODE is VOIDmode, return nothing in particular.
        !          2981:    UNSIGNEDP is not used in this case.
        !          2982: 
        !          2983:    Otherwise, return an rtx for the value stored.  This rtx
        !          2984:    has mode VALUE_MODE if that is convenient to do.
        !          2985:    In this case, UNSIGNEDP must be nonzero if the value is an unsigned type.
        !          2986: 
        !          2987:    ALIGN is the alignment that TARGET is known to have, measured in bytes.
        !          2988:    TOTAL_SIZE is the size in bytes of the structure, or -1 if varying.  */
        !          2989: 
        !          2990: static rtx
        !          2991: store_field (target, bitsize, bitpos, mode, exp, value_mode,
        !          2992:             unsignedp, align, total_size)
        !          2993:      rtx target;
        !          2994:      int bitsize, bitpos;
        !          2995:      enum machine_mode mode;
        !          2996:      tree exp;
        !          2997:      enum machine_mode value_mode;
        !          2998:      int unsignedp;
        !          2999:      int align;
        !          3000:      int total_size;
        !          3001: {
        !          3002:   HOST_WIDE_INT width_mask = 0;
        !          3003: 
        !          3004:   if (bitsize < HOST_BITS_PER_WIDE_INT)
        !          3005:     width_mask = ((HOST_WIDE_INT) 1 << bitsize) - 1;
        !          3006: 
        !          3007:   /* If we are storing into an unaligned field of an aligned union that is
        !          3008:      in a register, we may have the mode of TARGET being an integer mode but
        !          3009:      MODE == BLKmode.  In that case, get an aligned object whose size and
        !          3010:      alignment are the same as TARGET and store TARGET into it (we can avoid
        !          3011:      the store if the field being stored is the entire width of TARGET).  Then
        !          3012:      call ourselves recursively to store the field into a BLKmode version of
        !          3013:      that object.  Finally, load from the object into TARGET.  This is not
        !          3014:      very efficient in general, but should only be slightly more expensive
        !          3015:      than the otherwise-required unaligned accesses.  Perhaps this can be
        !          3016:      cleaned up later.  */
        !          3017: 
        !          3018:   if (mode == BLKmode
        !          3019:       && (GET_CODE (target) == REG || GET_CODE (target) == SUBREG))
        !          3020:     {
        !          3021:       rtx object = assign_stack_temp (GET_MODE (target),
        !          3022:                                      GET_MODE_SIZE (GET_MODE (target)), 0);
        !          3023:       rtx blk_object = copy_rtx (object);
        !          3024: 
        !          3025:       PUT_MODE (blk_object, BLKmode);
        !          3026: 
        !          3027:       if (bitsize != GET_MODE_BITSIZE (GET_MODE (target)))
        !          3028:        emit_move_insn (object, target);
        !          3029: 
        !          3030:       store_field (blk_object, bitsize, bitpos, mode, exp, VOIDmode, 0,
        !          3031:                   align, total_size);
        !          3032: 
        !          3033:       /* Even though we aren't returning target, we need to
        !          3034:         give it the updated value.  */
        !          3035:       emit_move_insn (target, object);
        !          3036: 
        !          3037:       return blk_object;
        !          3038:     }
        !          3039: 
        !          3040:   /* If the structure is in a register or if the component
        !          3041:      is a bit field, we cannot use addressing to access it.
        !          3042:      Use bit-field techniques or SUBREG to store in it.  */
        !          3043: 
        !          3044:   if (mode == VOIDmode
        !          3045:       || (mode != BLKmode && ! direct_store[(int) mode])
        !          3046:       || GET_CODE (target) == REG
        !          3047:       || GET_CODE (target) == SUBREG
        !          3048:       /* If the field isn't aligned enough to store as an ordinary memref,
        !          3049:         store it as a bit field.  */
        !          3050:       || (STRICT_ALIGNMENT
        !          3051:          && align * BITS_PER_UNIT < GET_MODE_ALIGNMENT (mode))
        !          3052:       || (STRICT_ALIGNMENT && bitpos % GET_MODE_ALIGNMENT (mode) != 0))
        !          3053:     {
        !          3054:       rtx temp = expand_expr (exp, NULL_RTX, VOIDmode, 0);
        !          3055: 
        !          3056:       /* Unless MODE is VOIDmode or BLKmode, convert TEMP to
        !          3057:         MODE.  */
        !          3058:       if (mode != VOIDmode && mode != BLKmode
        !          3059:          && mode != TYPE_MODE (TREE_TYPE (exp)))
        !          3060:        temp = convert_modes (mode, TYPE_MODE (TREE_TYPE (exp)), temp, 1);
        !          3061: 
        !          3062:       /* Store the value in the bitfield.  */
        !          3063:       store_bit_field (target, bitsize, bitpos, mode, temp, align, total_size);
        !          3064:       if (value_mode != VOIDmode)
        !          3065:        {
        !          3066:          /* The caller wants an rtx for the value.  */
        !          3067:          /* If possible, avoid refetching from the bitfield itself.  */
        !          3068:          if (width_mask != 0
        !          3069:              && ! (GET_CODE (target) == MEM && MEM_VOLATILE_P (target)))
        !          3070:            {
        !          3071:              tree count;
        !          3072:              enum machine_mode tmode;
        !          3073: 
        !          3074:              if (unsignedp)
        !          3075:                return expand_and (temp, GEN_INT (width_mask), NULL_RTX);
        !          3076:              tmode = GET_MODE (temp);
        !          3077:              if (tmode == VOIDmode)
        !          3078:                tmode = value_mode;
        !          3079:              count = build_int_2 (GET_MODE_BITSIZE (tmode) - bitsize, 0);
        !          3080:              temp = expand_shift (LSHIFT_EXPR, tmode, temp, count, 0, 0);
        !          3081:              return expand_shift (RSHIFT_EXPR, tmode, temp, count, 0, 0);
        !          3082:            }
        !          3083:          return extract_bit_field (target, bitsize, bitpos, unsignedp,
        !          3084:                                    NULL_RTX, value_mode, 0, align,
        !          3085:                                    total_size);
        !          3086:        }
        !          3087:       return const0_rtx;
        !          3088:     }
        !          3089:   else
        !          3090:     {
        !          3091:       rtx addr = XEXP (target, 0);
        !          3092:       rtx to_rtx;
        !          3093: 
        !          3094:       /* If a value is wanted, it must be the lhs;
        !          3095:         so make the address stable for multiple use.  */
        !          3096: 
        !          3097:       if (value_mode != VOIDmode && GET_CODE (addr) != REG
        !          3098:          && ! CONSTANT_ADDRESS_P (addr)
        !          3099:          /* A frame-pointer reference is already stable.  */
        !          3100:          && ! (GET_CODE (addr) == PLUS
        !          3101:                && GET_CODE (XEXP (addr, 1)) == CONST_INT
        !          3102:                && (XEXP (addr, 0) == virtual_incoming_args_rtx
        !          3103:                    || XEXP (addr, 0) == virtual_stack_vars_rtx)))
        !          3104:        addr = copy_to_reg (addr);
        !          3105: 
        !          3106:       /* Now build a reference to just the desired component.  */
        !          3107: 
        !          3108:       to_rtx = change_address (target, mode,
        !          3109:                               plus_constant (addr, (bitpos / BITS_PER_UNIT)));
        !          3110:       MEM_IN_STRUCT_P (to_rtx) = 1;
        !          3111: 
        !          3112:       return store_expr (exp, to_rtx, value_mode != VOIDmode);
        !          3113:     }
        !          3114: }
        !          3115: 
        !          3116: /* Given an expression EXP that may be a COMPONENT_REF, a BIT_FIELD_REF,
        !          3117:    or an ARRAY_REF, look for nested COMPONENT_REFs, BIT_FIELD_REFs, or
        !          3118:    ARRAY_REFs and find the ultimate containing object, which we return.
        !          3119: 
        !          3120:    We set *PBITSIZE to the size in bits that we want, *PBITPOS to the
        !          3121:    bit position, and *PUNSIGNEDP to the signedness of the field.
        !          3122:    If the position of the field is variable, we store a tree
        !          3123:    giving the variable offset (in units) in *POFFSET.
        !          3124:    This offset is in addition to the bit position.
        !          3125:    If the position is not variable, we store 0 in *POFFSET.
        !          3126: 
        !          3127:    If any of the extraction expressions is volatile,
        !          3128:    we store 1 in *PVOLATILEP.  Otherwise we don't change that.
        !          3129: 
        !          3130:    If the field is a bit-field, *PMODE is set to VOIDmode.  Otherwise, it
        !          3131:    is a mode that can be used to access the field.  In that case, *PBITSIZE
        !          3132:    is redundant.
        !          3133: 
        !          3134:    If the field describes a variable-sized object, *PMODE is set to
        !          3135:    VOIDmode and *PBITSIZE is set to -1.  An access cannot be made in
        !          3136:    this case, but the address of the object can be found.  */
        !          3137: 
        !          3138: tree
        !          3139: get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
        !          3140:                     punsignedp, pvolatilep)
        !          3141:      tree exp;
        !          3142:      int *pbitsize;
        !          3143:      int *pbitpos;
        !          3144:      tree *poffset;
        !          3145:      enum machine_mode *pmode;
        !          3146:      int *punsignedp;
        !          3147:      int *pvolatilep;
        !          3148: {
        !          3149:   tree orig_exp = exp;
        !          3150:   tree size_tree = 0;
        !          3151:   enum machine_mode mode = VOIDmode;
        !          3152:   tree offset = integer_zero_node;
        !          3153: 
        !          3154:   if (TREE_CODE (exp) == COMPONENT_REF)
        !          3155:     {
        !          3156:       size_tree = DECL_SIZE (TREE_OPERAND (exp, 1));
        !          3157:       if (! DECL_BIT_FIELD (TREE_OPERAND (exp, 1)))
        !          3158:        mode = DECL_MODE (TREE_OPERAND (exp, 1));
        !          3159:       *punsignedp = TREE_UNSIGNED (TREE_OPERAND (exp, 1));
        !          3160:     }
        !          3161:   else if (TREE_CODE (exp) == BIT_FIELD_REF)
        !          3162:     {
        !          3163:       size_tree = TREE_OPERAND (exp, 1);
        !          3164:       *punsignedp = TREE_UNSIGNED (exp);
        !          3165:     }
        !          3166:   else
        !          3167:     {
        !          3168:       mode = TYPE_MODE (TREE_TYPE (exp));
        !          3169:       *pbitsize = GET_MODE_BITSIZE (mode);
        !          3170:       *punsignedp = TREE_UNSIGNED (TREE_TYPE (exp));
        !          3171:     }
        !          3172:       
        !          3173:   if (size_tree)
        !          3174:     {
        !          3175:       if (TREE_CODE (size_tree) != INTEGER_CST)
        !          3176:        mode = BLKmode, *pbitsize = -1;
        !          3177:       else
        !          3178:        *pbitsize = TREE_INT_CST_LOW (size_tree);
        !          3179:     }
        !          3180: 
        !          3181:   /* Compute cumulative bit-offset for nested component-refs and array-refs,
        !          3182:      and find the ultimate containing object.  */
        !          3183: 
        !          3184:   *pbitpos = 0;
        !          3185: 
        !          3186:   while (1)
        !          3187:     {
        !          3188:       if (TREE_CODE (exp) == COMPONENT_REF || TREE_CODE (exp) == BIT_FIELD_REF)
        !          3189:        {
        !          3190:          tree pos = (TREE_CODE (exp) == COMPONENT_REF
        !          3191:                      ? DECL_FIELD_BITPOS (TREE_OPERAND (exp, 1))
        !          3192:                      : TREE_OPERAND (exp, 2));
        !          3193: 
        !          3194:          /* If this field hasn't been filled in yet, don't go
        !          3195:             past it.  This should only happen when folding expressions
        !          3196:             made during type construction.  */
        !          3197:          if (pos == 0)
        !          3198:            break;
        !          3199: 
        !          3200:          if (TREE_CODE (pos) == PLUS_EXPR)
        !          3201:            {
        !          3202:              tree constant, var;
        !          3203:              if (TREE_CODE (TREE_OPERAND (pos, 0)) == INTEGER_CST)
        !          3204:                {
        !          3205:                  constant = TREE_OPERAND (pos, 0);
        !          3206:                  var = TREE_OPERAND (pos, 1);
        !          3207:                }
        !          3208:              else if (TREE_CODE (TREE_OPERAND (pos, 1)) == INTEGER_CST)
        !          3209:                {
        !          3210:                  constant = TREE_OPERAND (pos, 1);
        !          3211:                  var = TREE_OPERAND (pos, 0);
        !          3212:                }
        !          3213:              else
        !          3214:                abort ();
        !          3215: 
        !          3216:              *pbitpos += TREE_INT_CST_LOW (constant);
        !          3217:              offset = size_binop (PLUS_EXPR, offset,
        !          3218:                                   size_binop (FLOOR_DIV_EXPR, var,
        !          3219:                                               size_int (BITS_PER_UNIT)));
        !          3220:            }
        !          3221:          else if (TREE_CODE (pos) == INTEGER_CST)
        !          3222:            *pbitpos += TREE_INT_CST_LOW (pos);
        !          3223:          else
        !          3224:            {
        !          3225:              /* Assume here that the offset is a multiple of a unit.
        !          3226:                 If not, there should be an explicitly added constant.  */
        !          3227:              offset = size_binop (PLUS_EXPR, offset,
        !          3228:                                   size_binop (FLOOR_DIV_EXPR, pos,
        !          3229:                                               size_int (BITS_PER_UNIT)));
        !          3230:            }
        !          3231:        }
        !          3232: 
        !          3233:       else if (TREE_CODE (exp) == ARRAY_REF)
        !          3234:        {
        !          3235:          /* This code is based on the code in case ARRAY_REF in expand_expr
        !          3236:             below.  We assume here that the size of an array element is
        !          3237:             always an integral multiple of BITS_PER_UNIT.  */
        !          3238: 
        !          3239:          tree index = TREE_OPERAND (exp, 1);
        !          3240:          tree domain = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (exp, 0)));
        !          3241:          tree low_bound
        !          3242:            = domain ? TYPE_MIN_VALUE (domain) : integer_zero_node;
        !          3243:          tree index_type = TREE_TYPE (index);
        !          3244: 
        !          3245:          if (! integer_zerop (low_bound))
        !          3246:            index = fold (build (MINUS_EXPR, index_type, index, low_bound));
        !          3247: 
        !          3248:          if (TYPE_PRECISION (index_type) != POINTER_SIZE)
        !          3249:            {
        !          3250:              index = convert (type_for_size (POINTER_SIZE, 0), index);
        !          3251:              index_type = TREE_TYPE (index);
        !          3252:            }
        !          3253: 
        !          3254:          index = fold (build (MULT_EXPR, index_type, index,
        !          3255:                               TYPE_SIZE (TREE_TYPE (exp))));
        !          3256: 
        !          3257:          if (TREE_CODE (index) == INTEGER_CST
        !          3258:              && TREE_INT_CST_HIGH (index) == 0)
        !          3259:            *pbitpos += TREE_INT_CST_LOW (index);
        !          3260:          else
        !          3261:            offset = size_binop (PLUS_EXPR, offset,
        !          3262:                                 size_binop (FLOOR_DIV_EXPR, index,
        !          3263:                                             size_int (BITS_PER_UNIT)));
        !          3264:        }
        !          3265:       else if (TREE_CODE (exp) != NON_LVALUE_EXPR
        !          3266:               && ! ((TREE_CODE (exp) == NOP_EXPR
        !          3267:                      || TREE_CODE (exp) == CONVERT_EXPR)
        !          3268:                     && (TYPE_MODE (TREE_TYPE (exp))
        !          3269:                         == TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))))
        !          3270:        break;
        !          3271: 
        !          3272:       /* If any reference in the chain is volatile, the effect is volatile.  */
        !          3273:       if (TREE_THIS_VOLATILE (exp))
        !          3274:        *pvolatilep = 1;
        !          3275:       exp = TREE_OPERAND (exp, 0);
        !          3276:     }
        !          3277: 
        !          3278:   /* If this was a bit-field, see if there is a mode that allows direct
        !          3279:      access in case EXP is in memory.  */
        !          3280:   if (mode == VOIDmode && *pbitsize != 0 && *pbitpos % *pbitsize == 0)
        !          3281:     {
        !          3282:       mode = mode_for_size (*pbitsize, MODE_INT, 0);
        !          3283:       if (mode == BLKmode)
        !          3284:        mode = VOIDmode;
        !          3285:     }
        !          3286: 
        !          3287:   if (integer_zerop (offset))
        !          3288:     offset = 0;
        !          3289: 
        !          3290:   if (offset != 0 && contains_placeholder_p (offset))
        !          3291:     offset = build (WITH_RECORD_EXPR, sizetype, offset, orig_exp);
        !          3292: 
        !          3293:   *pmode = mode;
        !          3294:   *poffset = offset;
        !          3295:   return exp;
        !          3296: }
        !          3297: 
        !          3298: /* Given an rtx VALUE that may contain additions and multiplications,
        !          3299:    return an equivalent value that just refers to a register or memory.
        !          3300:    This is done by generating instructions to perform the arithmetic
        !          3301:    and returning a pseudo-register containing the value.
        !          3302: 
        !          3303:    The returned value may be a REG, SUBREG, MEM or constant.  */
        !          3304: 
        !          3305: rtx
        !          3306: force_operand (value, target)
        !          3307:      rtx value, target;
        !          3308: {
        !          3309:   register optab binoptab = 0;
        !          3310:   /* Use a temporary to force order of execution of calls to
        !          3311:      `force_operand'.  */
        !          3312:   rtx tmp;
        !          3313:   register rtx op2;
        !          3314:   /* Use subtarget as the target for operand 0 of a binary operation.  */
        !          3315:   register rtx subtarget = (target != 0 && GET_CODE (target) == REG ? target : 0);
        !          3316: 
        !          3317:   if (GET_CODE (value) == PLUS)
        !          3318:     binoptab = add_optab;
        !          3319:   else if (GET_CODE (value) == MINUS)
        !          3320:     binoptab = sub_optab;
        !          3321:   else if (GET_CODE (value) == MULT)
        !          3322:     {
        !          3323:       op2 = XEXP (value, 1);
        !          3324:       if (!CONSTANT_P (op2)
        !          3325:          && !(GET_CODE (op2) == REG && op2 != subtarget))
        !          3326:        subtarget = 0;
        !          3327:       tmp = force_operand (XEXP (value, 0), subtarget);
        !          3328:       return expand_mult (GET_MODE (value), tmp,
        !          3329:                          force_operand (op2, NULL_RTX),
        !          3330:                          target, 0);
        !          3331:     }
        !          3332: 
        !          3333:   if (binoptab)
        !          3334:     {
        !          3335:       op2 = XEXP (value, 1);
        !          3336:       if (!CONSTANT_P (op2)
        !          3337:          && !(GET_CODE (op2) == REG && op2 != subtarget))
        !          3338:        subtarget = 0;
        !          3339:       if (binoptab == sub_optab && GET_CODE (op2) == CONST_INT)
        !          3340:        {
        !          3341:          binoptab = add_optab;
        !          3342:          op2 = negate_rtx (GET_MODE (value), op2);
        !          3343:        }
        !          3344: 
        !          3345:       /* Check for an addition with OP2 a constant integer and our first
        !          3346:         operand a PLUS of a virtual register and something else.  In that
        !          3347:         case, we want to emit the sum of the virtual register and the
        !          3348:         constant first and then add the other value.  This allows virtual
        !          3349:         register instantiation to simply modify the constant rather than
        !          3350:         creating another one around this addition.  */
        !          3351:       if (binoptab == add_optab && GET_CODE (op2) == CONST_INT
        !          3352:          && GET_CODE (XEXP (value, 0)) == PLUS
        !          3353:          && GET_CODE (XEXP (XEXP (value, 0), 0)) == REG
        !          3354:          && REGNO (XEXP (XEXP (value, 0), 0)) >= FIRST_VIRTUAL_REGISTER
        !          3355:          && REGNO (XEXP (XEXP (value, 0), 0)) <= LAST_VIRTUAL_REGISTER)
        !          3356:        {
        !          3357:          rtx temp = expand_binop (GET_MODE (value), binoptab,
        !          3358:                                   XEXP (XEXP (value, 0), 0), op2,
        !          3359:                                   subtarget, 0, OPTAB_LIB_WIDEN);
        !          3360:          return expand_binop (GET_MODE (value), binoptab, temp,
        !          3361:                               force_operand (XEXP (XEXP (value, 0), 1), 0),
        !          3362:                               target, 0, OPTAB_LIB_WIDEN);
        !          3363:        }
        !          3364:                                   
        !          3365:       tmp = force_operand (XEXP (value, 0), subtarget);
        !          3366:       return expand_binop (GET_MODE (value), binoptab, tmp,
        !          3367:                           force_operand (op2, NULL_RTX),
        !          3368:                           target, 0, OPTAB_LIB_WIDEN);
        !          3369:       /* We give UNSIGNEDP = 0 to expand_binop
        !          3370:         because the only operations we are expanding here are signed ones.  */
        !          3371:     }
        !          3372:   return value;
        !          3373: }
        !          3374: 
        !          3375: /* Subroutine of expand_expr:
        !          3376:    save the non-copied parts (LIST) of an expr (LHS), and return a list
        !          3377:    which can restore these values to their previous values,
        !          3378:    should something modify their storage.  */
        !          3379: 
        !          3380: static tree
        !          3381: save_noncopied_parts (lhs, list)
        !          3382:      tree lhs;
        !          3383:      tree list;
        !          3384: {
        !          3385:   tree tail;
        !          3386:   tree parts = 0;
        !          3387: 
        !          3388:   for (tail = list; tail; tail = TREE_CHAIN (tail))
        !          3389:     if (TREE_CODE (TREE_VALUE (tail)) == TREE_LIST)
        !          3390:       parts = chainon (parts, save_noncopied_parts (lhs, TREE_VALUE (tail)));
        !          3391:     else
        !          3392:       {
        !          3393:        tree part = TREE_VALUE (tail);
        !          3394:        tree part_type = TREE_TYPE (part);
        !          3395:        tree to_be_saved = build (COMPONENT_REF, part_type, lhs, part);
        !          3396:        rtx target = assign_stack_temp (TYPE_MODE (part_type),
        !          3397:                                        int_size_in_bytes (part_type), 0);
        !          3398:        if (! memory_address_p (TYPE_MODE (part_type), XEXP (target, 0)))
        !          3399:          target = change_address (target, TYPE_MODE (part_type), NULL_RTX);
        !          3400:        parts = tree_cons (to_be_saved,
        !          3401:                           build (RTL_EXPR, part_type, NULL_TREE,
        !          3402:                                  (tree) target),
        !          3403:                           parts);
        !          3404:        store_expr (TREE_PURPOSE (parts), RTL_EXPR_RTL (TREE_VALUE (parts)), 0);
        !          3405:       }
        !          3406:   return parts;
        !          3407: }
        !          3408: 
        !          3409: /* Subroutine of expand_expr:
        !          3410:    record the non-copied parts (LIST) of an expr (LHS), and return a list
        !          3411:    which specifies the initial values of these parts.  */
        !          3412: 
        !          3413: static tree
        !          3414: init_noncopied_parts (lhs, list)
        !          3415:      tree lhs;
        !          3416:      tree list;
        !          3417: {
        !          3418:   tree tail;
        !          3419:   tree parts = 0;
        !          3420: 
        !          3421:   for (tail = list; tail; tail = TREE_CHAIN (tail))
        !          3422:     if (TREE_CODE (TREE_VALUE (tail)) == TREE_LIST)
        !          3423:       parts = chainon (parts, init_noncopied_parts (lhs, TREE_VALUE (tail)));
        !          3424:     else
        !          3425:       {
        !          3426:        tree part = TREE_VALUE (tail);
        !          3427:        tree part_type = TREE_TYPE (part);
        !          3428:        tree to_be_initialized = build (COMPONENT_REF, part_type, lhs, part);
        !          3429:        parts = tree_cons (TREE_PURPOSE (tail), to_be_initialized, parts);
        !          3430:       }
        !          3431:   return parts;
        !          3432: }
        !          3433: 
        !          3434: /* Subroutine of expand_expr: return nonzero iff there is no way that
        !          3435:    EXP can reference X, which is being modified.  */
        !          3436: 
        !          3437: static int
        !          3438: safe_from_p (x, exp)
        !          3439:      rtx x;
        !          3440:      tree exp;
        !          3441: {
        !          3442:   rtx exp_rtl = 0;
        !          3443:   int i, nops;
        !          3444: 
        !          3445:   if (x == 0)
        !          3446:     return 1;
        !          3447: 
        !          3448:   /* If this is a subreg of a hard register, declare it unsafe, otherwise,
        !          3449:      find the underlying pseudo.  */
        !          3450:   if (GET_CODE (x) == SUBREG)
        !          3451:     {
        !          3452:       x = SUBREG_REG (x);
        !          3453:       if (GET_CODE (x) == REG && REGNO (x) < FIRST_PSEUDO_REGISTER)
        !          3454:        return 0;
        !          3455:     }
        !          3456: 
        !          3457:   /* If X is a location in the outgoing argument area, it is always safe.  */
        !          3458:   if (GET_CODE (x) == MEM
        !          3459:       && (XEXP (x, 0) == virtual_outgoing_args_rtx
        !          3460:          || (GET_CODE (XEXP (x, 0)) == PLUS
        !          3461:              && XEXP (XEXP (x, 0), 0) == virtual_outgoing_args_rtx)))
        !          3462:     return 1;
        !          3463: 
        !          3464:   switch (TREE_CODE_CLASS (TREE_CODE (exp)))
        !          3465:     {
        !          3466:     case 'd':
        !          3467:       exp_rtl = DECL_RTL (exp);
        !          3468:       break;
        !          3469: 
        !          3470:     case 'c':
        !          3471:       return 1;
        !          3472: 
        !          3473:     case 'x':
        !          3474:       if (TREE_CODE (exp) == TREE_LIST)
        !          3475:        return ((TREE_VALUE (exp) == 0
        !          3476:                 || safe_from_p (x, TREE_VALUE (exp)))
        !          3477:                && (TREE_CHAIN (exp) == 0
        !          3478:                    || safe_from_p (x, TREE_CHAIN (exp))));
        !          3479:       else
        !          3480:        return 0;
        !          3481: 
        !          3482:     case '1':
        !          3483:       return safe_from_p (x, TREE_OPERAND (exp, 0));
        !          3484: 
        !          3485:     case '2':
        !          3486:     case '<':
        !          3487:       return (safe_from_p (x, TREE_OPERAND (exp, 0))
        !          3488:              && safe_from_p (x, TREE_OPERAND (exp, 1)));
        !          3489: 
        !          3490:     case 'e':
        !          3491:     case 'r':
        !          3492:       /* Now do code-specific tests.  EXP_RTL is set to any rtx we find in
        !          3493:         the expression.  If it is set, we conflict iff we are that rtx or
        !          3494:         both are in memory.  Otherwise, we check all operands of the
        !          3495:         expression recursively.  */
        !          3496: 
        !          3497:       switch (TREE_CODE (exp))
        !          3498:        {
        !          3499:        case ADDR_EXPR:
        !          3500:          return (staticp (TREE_OPERAND (exp, 0))
        !          3501:                  || safe_from_p (x, TREE_OPERAND (exp, 0)));
        !          3502: 
        !          3503:        case INDIRECT_REF:
        !          3504:          if (GET_CODE (x) == MEM)
        !          3505:            return 0;
        !          3506:          break;
        !          3507: 
        !          3508:        case CALL_EXPR:
        !          3509:          exp_rtl = CALL_EXPR_RTL (exp);
        !          3510:          if (exp_rtl == 0)
        !          3511:            {
        !          3512:              /* Assume that the call will clobber all hard registers and
        !          3513:                 all of memory.  */
        !          3514:              if ((GET_CODE (x) == REG && REGNO (x) < FIRST_PSEUDO_REGISTER)
        !          3515:                  || GET_CODE (x) == MEM)
        !          3516:                return 0;
        !          3517:            }
        !          3518: 
        !          3519:          break;
        !          3520: 
        !          3521:        case RTL_EXPR:
        !          3522:          exp_rtl = RTL_EXPR_RTL (exp);
        !          3523:          if (exp_rtl == 0)
        !          3524:            /* We don't know what this can modify.  */
        !          3525:            return 0;
        !          3526: 
        !          3527:          break;
        !          3528: 
        !          3529:        case WITH_CLEANUP_EXPR:
        !          3530:          exp_rtl = RTL_EXPR_RTL (exp);
        !          3531:          break;
        !          3532: 
        !          3533:        case SAVE_EXPR:
        !          3534:          exp_rtl = SAVE_EXPR_RTL (exp);
        !          3535:          break;
        !          3536: 
        !          3537:        case BIND_EXPR:
        !          3538:          /* The only operand we look at is operand 1.  The rest aren't
        !          3539:             part of the expression.  */
        !          3540:          return safe_from_p (x, TREE_OPERAND (exp, 1));
        !          3541: 
        !          3542:        case METHOD_CALL_EXPR:
        !          3543:          /* This takes a rtx argument, but shouldn't appear here. */
        !          3544:          abort ();
        !          3545:        }
        !          3546: 
        !          3547:       /* If we have an rtx, we do not need to scan our operands.  */
        !          3548:       if (exp_rtl)
        !          3549:        break;
        !          3550: 
        !          3551:       nops = tree_code_length[(int) TREE_CODE (exp)];
        !          3552:       for (i = 0; i < nops; i++)
        !          3553:        if (TREE_OPERAND (exp, i) != 0
        !          3554:            && ! safe_from_p (x, TREE_OPERAND (exp, i)))
        !          3555:          return 0;
        !          3556:     }
        !          3557: 
        !          3558:   /* If we have an rtl, find any enclosed object.  Then see if we conflict
        !          3559:      with it.  */
        !          3560:   if (exp_rtl)
        !          3561:     {
        !          3562:       if (GET_CODE (exp_rtl) == SUBREG)
        !          3563:        {
        !          3564:          exp_rtl = SUBREG_REG (exp_rtl);
        !          3565:          if (GET_CODE (exp_rtl) == REG
        !          3566:              && REGNO (exp_rtl) < FIRST_PSEUDO_REGISTER)
        !          3567:            return 0;
        !          3568:        }
        !          3569: 
        !          3570:       /* If the rtl is X, then it is not safe.  Otherwise, it is unless both
        !          3571:         are memory and EXP is not readonly.  */
        !          3572:       return ! (rtx_equal_p (x, exp_rtl)
        !          3573:                || (GET_CODE (x) == MEM && GET_CODE (exp_rtl) == MEM
        !          3574:                    && ! TREE_READONLY (exp)));
        !          3575:     }
        !          3576: 
        !          3577:   /* If we reach here, it is safe.  */
        !          3578:   return 1;
        !          3579: }
        !          3580: 
        !          3581: /* Subroutine of expand_expr: return nonzero iff EXP is an
        !          3582:    expression whose type is statically determinable.  */
        !          3583: 
        !          3584: static int
        !          3585: fixed_type_p (exp)
        !          3586:      tree exp;
        !          3587: {
        !          3588:   if (TREE_CODE (exp) == PARM_DECL
        !          3589:       || TREE_CODE (exp) == VAR_DECL
        !          3590:       || TREE_CODE (exp) == CALL_EXPR || TREE_CODE (exp) == TARGET_EXPR
        !          3591:       || TREE_CODE (exp) == COMPONENT_REF
        !          3592:       || TREE_CODE (exp) == ARRAY_REF)
        !          3593:     return 1;
        !          3594:   return 0;
        !          3595: }
        !          3596: 
        !          3597: /* expand_expr: generate code for computing expression EXP.
        !          3598:    An rtx for the computed value is returned.  The value is never null.
        !          3599:    In the case of a void EXP, const0_rtx is returned.
        !          3600: 
        !          3601:    The value may be stored in TARGET if TARGET is nonzero.
        !          3602:    TARGET is just a suggestion; callers must assume that
        !          3603:    the rtx returned may not be the same as TARGET.
        !          3604: 
        !          3605:    If TARGET is CONST0_RTX, it means that the value will be ignored.
        !          3606: 
        !          3607:    If TMODE is not VOIDmode, it suggests generating the
        !          3608:    result in mode TMODE.  But this is done only when convenient.
        !          3609:    Otherwise, TMODE is ignored and the value generated in its natural mode.
        !          3610:    TMODE is just a suggestion; callers must assume that
        !          3611:    the rtx returned may not have mode TMODE.
        !          3612: 
        !          3613:    EXPAND_CONST_ADDRESS says that it is okay to return a MEM
        !          3614:    with a constant address even if that address is not normally legitimate.
        !          3615:    EXPAND_INITIALIZER and EXPAND_SUM also have this effect.
        !          3616: 
        !          3617:    If MODIFIER is EXPAND_SUM then when EXP is an addition
        !          3618:    we can return an rtx of the form (MULT (REG ...) (CONST_INT ...))
        !          3619:    or a nest of (PLUS ...) and (MINUS ...) where the terms are
        !          3620:    products as above, or REG or MEM, or constant.
        !          3621:    Ordinarily in such cases we would output mul or add instructions
        !          3622:    and then return a pseudo reg containing the sum.
        !          3623: 
        !          3624:    EXPAND_INITIALIZER is much like EXPAND_SUM except that
        !          3625:    it also marks a label as absolutely required (it can't be dead).
        !          3626:    It also makes a ZERO_EXTEND or SIGN_EXTEND instead of emitting extend insns.
        !          3627:    This is used for outputting expressions used in initializers.  */
        !          3628: 
        !          3629: rtx
        !          3630: expand_expr (exp, target, tmode, modifier)
        !          3631:      register tree exp;
        !          3632:      rtx target;
        !          3633:      enum machine_mode tmode;
        !          3634:      enum expand_modifier modifier;
        !          3635: {
        !          3636:   /* Chain of pending expressions for PLACEHOLDER_EXPR to replace.
        !          3637:      This is static so it will be accessible to our recursive callees.  */
        !          3638:   static tree placeholder_list = 0;
        !          3639:   register rtx op0, op1, temp;
        !          3640:   tree type = TREE_TYPE (exp);
        !          3641:   int unsignedp = TREE_UNSIGNED (type);
        !          3642:   register enum machine_mode mode = TYPE_MODE (type);
        !          3643:   register enum tree_code code = TREE_CODE (exp);
        !          3644:   optab this_optab;
        !          3645:   /* Use subtarget as the target for operand 0 of a binary operation.  */
        !          3646:   rtx subtarget = (target != 0 && GET_CODE (target) == REG ? target : 0);
        !          3647:   rtx original_target = target;
        !          3648:   /* Maybe defer this until sure not doing bytecode?  */
        !          3649:   int ignore = (target == const0_rtx
        !          3650:                || ((code == NON_LVALUE_EXPR || code == NOP_EXPR
        !          3651:                     || code == CONVERT_EXPR || code == REFERENCE_EXPR
        !          3652:                     || code == COND_EXPR)
        !          3653:                    && TREE_CODE (type) == VOID_TYPE));
        !          3654:   tree context;
        !          3655: 
        !          3656: 
        !          3657:   if (output_bytecode)
        !          3658:     {
        !          3659:       bc_expand_expr (exp);
        !          3660:       return NULL;
        !          3661:     }
        !          3662: 
        !          3663:   /* Don't use hard regs as subtargets, because the combiner
        !          3664:      can only handle pseudo regs.  */
        !          3665:   if (subtarget && REGNO (subtarget) < FIRST_PSEUDO_REGISTER)
        !          3666:     subtarget = 0;
        !          3667:   /* Avoid subtargets inside loops,
        !          3668:      since they hide some invariant expressions.  */
        !          3669:   if (preserve_subexpressions_p ())
        !          3670:     subtarget = 0;
        !          3671: 
        !          3672:   /* If we are going to ignore this result, we need only do something
        !          3673:      if there is a side-effect somewhere in the expression.  If there
        !          3674:      is, short-circuit the most common cases here.  Note that we must
        !          3675:      not call expand_expr with anything but const0_rtx in case this
        !          3676:      is an initial expansion of a size that contains a PLACEHOLDER_EXPR.  */
        !          3677: 
        !          3678:   if (ignore)
        !          3679:     {
        !          3680:       if (! TREE_SIDE_EFFECTS (exp))
        !          3681:        return const0_rtx;
        !          3682: 
        !          3683:       /* Ensure we reference a volatile object even if value is ignored.  */
        !          3684:       if (TREE_THIS_VOLATILE (exp)
        !          3685:          && TREE_CODE (exp) != FUNCTION_DECL
        !          3686:          && mode != VOIDmode && mode != BLKmode)
        !          3687:        {
        !          3688:          temp = expand_expr (exp, NULL_RTX, VOIDmode, modifier);
        !          3689:          if (GET_CODE (temp) == MEM)
        !          3690:            temp = copy_to_reg (temp);
        !          3691:          return const0_rtx;
        !          3692:        }
        !          3693: 
        !          3694:       if (TREE_CODE_CLASS (code) == '1')
        !          3695:        return expand_expr (TREE_OPERAND (exp, 0), const0_rtx,
        !          3696:                            VOIDmode, modifier);
        !          3697:       else if (TREE_CODE_CLASS (code) == '2'
        !          3698:               || TREE_CODE_CLASS (code) == '<')
        !          3699:        {
        !          3700:          expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, modifier);
        !          3701:          expand_expr (TREE_OPERAND (exp, 1), const0_rtx, VOIDmode, modifier);
        !          3702:          return const0_rtx;
        !          3703:        }
        !          3704:       else if ((code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR)
        !          3705:               && ! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 1)))
        !          3706:        /* If the second operand has no side effects, just evaluate
        !          3707:           the first. */
        !          3708:        return expand_expr (TREE_OPERAND (exp, 0), const0_rtx,
        !          3709:                            VOIDmode, modifier);
        !          3710: 
        !          3711:       target = 0;
        !          3712:     }
        !          3713: 
        !          3714:   /* If will do cse, generate all results into pseudo registers
        !          3715:      since 1) that allows cse to find more things
        !          3716:      and 2) otherwise cse could produce an insn the machine
        !          3717:      cannot support.  */
        !          3718: 
        !          3719:   if (! cse_not_expected && mode != BLKmode && target
        !          3720:       && (GET_CODE (target) != REG || REGNO (target) < FIRST_PSEUDO_REGISTER))
        !          3721:     target = subtarget;
        !          3722: 
        !          3723:   switch (code)
        !          3724:     {
        !          3725:     case LABEL_DECL:
        !          3726:       {
        !          3727:        tree function = decl_function_context (exp);
        !          3728:        /* Handle using a label in a containing function.  */
        !          3729:        if (function != current_function_decl && function != 0)
        !          3730:          {
        !          3731:            struct function *p = find_function_data (function);
        !          3732:            /* Allocate in the memory associated with the function
        !          3733:               that the label is in.  */
        !          3734:            push_obstacks (p->function_obstack,
        !          3735:                           p->function_maybepermanent_obstack);
        !          3736: 
        !          3737:            p->forced_labels = gen_rtx (EXPR_LIST, VOIDmode,
        !          3738:                                        label_rtx (exp), p->forced_labels);
        !          3739:            pop_obstacks ();
        !          3740:          }
        !          3741:        else if (modifier == EXPAND_INITIALIZER)
        !          3742:          forced_labels = gen_rtx (EXPR_LIST, VOIDmode,
        !          3743:                                   label_rtx (exp), forced_labels);
        !          3744:        temp = gen_rtx (MEM, FUNCTION_MODE,
        !          3745:                        gen_rtx (LABEL_REF, Pmode, label_rtx (exp)));
        !          3746:        if (function != current_function_decl && function != 0)
        !          3747:          LABEL_REF_NONLOCAL_P (XEXP (temp, 0)) = 1;
        !          3748:        return temp;
        !          3749:       }
        !          3750: 
        !          3751:     case PARM_DECL:
        !          3752:       if (DECL_RTL (exp) == 0)
        !          3753:        {
        !          3754:          error_with_decl (exp, "prior parameter's size depends on `%s'");
        !          3755:          return CONST0_RTX (mode);
        !          3756:        }
        !          3757: 
        !          3758:     case VAR_DECL:
        !          3759:       /* If a static var's type was incomplete when the decl was written,
        !          3760:         but the type is complete now, lay out the decl now.  */
        !          3761:       if (DECL_SIZE (exp) == 0 && TYPE_SIZE (TREE_TYPE (exp)) != 0
        !          3762:          && (TREE_STATIC (exp) || DECL_EXTERNAL (exp)))
        !          3763:        {
        !          3764:          push_obstacks_nochange ();
        !          3765:          end_temporary_allocation ();
        !          3766:          layout_decl (exp, 0);
        !          3767:          PUT_MODE (DECL_RTL (exp), DECL_MODE (exp));
        !          3768:          pop_obstacks ();
        !          3769:        }
        !          3770:     case FUNCTION_DECL:
        !          3771:     case RESULT_DECL:
        !          3772:       if (DECL_RTL (exp) == 0)
        !          3773:        abort ();
        !          3774:       /* Ensure variable marked as used even if it doesn't go through
        !          3775:         a parser.  If it hasn't be used yet, write out an external
        !          3776:         definition.  */
        !          3777:       if (! TREE_USED (exp))
        !          3778:        {
        !          3779:          assemble_external (exp);
        !          3780:          TREE_USED (exp) = 1;
        !          3781:        }
        !          3782: 
        !          3783:       /* Handle variables inherited from containing functions.  */
        !          3784:       context = decl_function_context (exp);
        !          3785: 
        !          3786:       /* We treat inline_function_decl as an alias for the current function
        !          3787:         because that is the inline function whose vars, types, etc.
        !          3788:         are being merged into the current function.
        !          3789:         See expand_inline_function.  */
        !          3790:       if (context != 0 && context != current_function_decl
        !          3791:          && context != inline_function_decl
        !          3792:          /* If var is static, we don't need a static chain to access it.  */
        !          3793:          && ! (GET_CODE (DECL_RTL (exp)) == MEM
        !          3794:                && CONSTANT_P (XEXP (DECL_RTL (exp), 0))))
        !          3795:        {
        !          3796:          rtx addr;
        !          3797: 
        !          3798:          /* Mark as non-local and addressable.  */
        !          3799:          DECL_NONLOCAL (exp) = 1;
        !          3800:          mark_addressable (exp);
        !          3801:          if (GET_CODE (DECL_RTL (exp)) != MEM)
        !          3802:            abort ();
        !          3803:          addr = XEXP (DECL_RTL (exp), 0);
        !          3804:          if (GET_CODE (addr) == MEM)
        !          3805:            addr = gen_rtx (MEM, Pmode, fix_lexical_addr (XEXP (addr, 0), exp));
        !          3806:          else
        !          3807:            addr = fix_lexical_addr (addr, exp);
        !          3808:          return change_address (DECL_RTL (exp), mode, addr);
        !          3809:        }
        !          3810: 
        !          3811:       /* This is the case of an array whose size is to be determined
        !          3812:         from its initializer, while the initializer is still being parsed.
        !          3813:         See expand_decl.  */
        !          3814:       if (GET_CODE (DECL_RTL (exp)) == MEM
        !          3815:          && GET_CODE (XEXP (DECL_RTL (exp), 0)) == REG)
        !          3816:        return change_address (DECL_RTL (exp), GET_MODE (DECL_RTL (exp)),
        !          3817:                               XEXP (DECL_RTL (exp), 0));
        !          3818:       if (GET_CODE (DECL_RTL (exp)) == MEM
        !          3819:          && modifier != EXPAND_CONST_ADDRESS
        !          3820:          && modifier != EXPAND_SUM
        !          3821:          && modifier != EXPAND_INITIALIZER)
        !          3822:        {
        !          3823:          /* DECL_RTL probably contains a constant address.
        !          3824:             On RISC machines where a constant address isn't valid,
        !          3825:             make some insns to get that address into a register.  */
        !          3826:          if (!memory_address_p (DECL_MODE (exp), XEXP (DECL_RTL (exp), 0))
        !          3827:              || (flag_force_addr
        !          3828:                  && CONSTANT_ADDRESS_P (XEXP (DECL_RTL (exp), 0))))
        !          3829:            return change_address (DECL_RTL (exp), VOIDmode,
        !          3830:                                   copy_rtx (XEXP (DECL_RTL (exp), 0)));
        !          3831:        }
        !          3832: 
        !          3833:       /* If the mode of DECL_RTL does not match that of the decl, it
        !          3834:         must be a promoted value.  We return a SUBREG of the wanted mode,
        !          3835:         but mark it so that we know that it was already extended.  */
        !          3836: 
        !          3837:       if (GET_CODE (DECL_RTL (exp)) == REG
        !          3838:          && GET_MODE (DECL_RTL (exp)) != mode)
        !          3839:        {
        !          3840:          enum machine_mode decl_mode = DECL_MODE (exp);
        !          3841: 
        !          3842:          /* Get the signedness used for this variable.  Ensure we get the
        !          3843:             same mode we got when the variable was declared.  */
        !          3844: 
        !          3845:          PROMOTE_MODE (decl_mode, unsignedp, type);
        !          3846: 
        !          3847:          if (decl_mode != GET_MODE (DECL_RTL (exp)))
        !          3848:            abort ();
        !          3849: 
        !          3850:          temp = gen_rtx (SUBREG, mode, DECL_RTL (exp), 0);
        !          3851:          SUBREG_PROMOTED_VAR_P (temp) = 1;
        !          3852:          SUBREG_PROMOTED_UNSIGNED_P (temp) = unsignedp;
        !          3853:          return temp;
        !          3854:        }
        !          3855: 
        !          3856:       /*
        !          3857:       if (code == VAR_DECL 
        !          3858:          && modifier == EXPAND_NORMAL
        !          3859:          && TREE_SELF_OFFSET (exp))
        !          3860:        {
        !          3861:          rtx op0 = memory_address (mode, XEXP (DECL_RTL (exp), 0));
        !          3862:          rtx op1 = gen_rtx (PLUS, mode, op0, DECL_RTL (exp));
        !          3863:          temp = gen_rtx (MEM, mode, memory_address (mode, op1));
        !          3864:          MEM_IN_STRUCT_P (temp) = 1;
        !          3865:          MEM_VOLATILE_P (temp) = TREE_THIS_VOLATILE (exp);
        !          3866:          return temp;
        !          3867:        }
        !          3868:       else
        !          3869:       */
        !          3870:       return DECL_RTL (exp);
        !          3871: 
        !          3872:     case INTEGER_CST:
        !          3873:       return immed_double_const (TREE_INT_CST_LOW (exp),
        !          3874:                                 TREE_INT_CST_HIGH (exp),
        !          3875:                                 mode);
        !          3876: 
        !          3877:     case CONST_DECL:
        !          3878:       return expand_expr (DECL_INITIAL (exp), target, VOIDmode, 0);
        !          3879: 
        !          3880:     case REAL_CST:
        !          3881:       /* If optimized, generate immediate CONST_DOUBLE
        !          3882:         which will be turned into memory by reload if necessary. 
        !          3883:      
        !          3884:         We used to force a register so that loop.c could see it.  But
        !          3885:         this does not allow gen_* patterns to perform optimizations with
        !          3886:         the constants.  It also produces two insns in cases like "x = 1.0;".
        !          3887:         On most machines, floating-point constants are not permitted in
        !          3888:         many insns, so we'd end up copying it to a register in any case.
        !          3889: 
        !          3890:         Now, we do the copying in expand_binop, if appropriate.  */
        !          3891:       return immed_real_const (exp);
        !          3892: 
        !          3893:     case COMPLEX_CST:
        !          3894:     case STRING_CST:
        !          3895:       if (! TREE_CST_RTL (exp))
        !          3896:        output_constant_def (exp);
        !          3897: 
        !          3898:       /* TREE_CST_RTL probably contains a constant address.
        !          3899:         On RISC machines where a constant address isn't valid,
        !          3900:         make some insns to get that address into a register.  */
        !          3901:       if (GET_CODE (TREE_CST_RTL (exp)) == MEM
        !          3902:          && modifier != EXPAND_CONST_ADDRESS
        !          3903:          && modifier != EXPAND_INITIALIZER
        !          3904:          && modifier != EXPAND_SUM
        !          3905:          && !memory_address_p (mode, XEXP (TREE_CST_RTL (exp), 0)))
        !          3906:        return change_address (TREE_CST_RTL (exp), VOIDmode,
        !          3907:                               copy_rtx (XEXP (TREE_CST_RTL (exp), 0)));
        !          3908:       return TREE_CST_RTL (exp);
        !          3909: 
        !          3910:     case SAVE_EXPR:
        !          3911:       context = decl_function_context (exp);
        !          3912:       /* We treat inline_function_decl as an alias for the current function
        !          3913:         because that is the inline function whose vars, types, etc.
        !          3914:         are being merged into the current function.
        !          3915:         See expand_inline_function.  */
        !          3916:       if (context == current_function_decl || context == inline_function_decl)
        !          3917:        context = 0;
        !          3918: 
        !          3919:       /* If this is non-local, handle it.  */
        !          3920:       if (context)
        !          3921:        {
        !          3922:          temp = SAVE_EXPR_RTL (exp);
        !          3923:          if (temp && GET_CODE (temp) == REG)
        !          3924:            {
        !          3925:              put_var_into_stack (exp);
        !          3926:              temp = SAVE_EXPR_RTL (exp);
        !          3927:            }
        !          3928:          if (temp == 0 || GET_CODE (temp) != MEM)
        !          3929:            abort ();
        !          3930:          return change_address (temp, mode,
        !          3931:                                 fix_lexical_addr (XEXP (temp, 0), exp));
        !          3932:        }
        !          3933:       if (SAVE_EXPR_RTL (exp) == 0)
        !          3934:        {
        !          3935:          if (mode == BLKmode)
        !          3936:            {
        !          3937:              temp
        !          3938:                = assign_stack_temp (mode, int_size_in_bytes (type), 0);
        !          3939:              MEM_IN_STRUCT_P (temp)
        !          3940:                = (TREE_CODE (type) == RECORD_TYPE
        !          3941:                   || TREE_CODE (type) == UNION_TYPE
        !          3942:                   || TREE_CODE (type) == QUAL_UNION_TYPE
        !          3943:                   || TREE_CODE (type) == ARRAY_TYPE);
        !          3944:            }
        !          3945:          else
        !          3946:            {
        !          3947:              enum machine_mode var_mode = mode;
        !          3948: 
        !          3949:              if (TREE_CODE (type) == INTEGER_TYPE
        !          3950:                  || TREE_CODE (type) == ENUMERAL_TYPE
        !          3951:                  || TREE_CODE (type) == BOOLEAN_TYPE
        !          3952:                  || TREE_CODE (type) == CHAR_TYPE
        !          3953:                  || TREE_CODE (type) == REAL_TYPE
        !          3954:                  || TREE_CODE (type) == POINTER_TYPE
        !          3955:                  || TREE_CODE (type) == OFFSET_TYPE)
        !          3956:                {
        !          3957:                  PROMOTE_MODE (var_mode, unsignedp, type);
        !          3958:                }
        !          3959: 
        !          3960:              temp = gen_reg_rtx (var_mode);
        !          3961:            }
        !          3962: 
        !          3963:          SAVE_EXPR_RTL (exp) = temp;
        !          3964:          if (!optimize && GET_CODE (temp) == REG)
        !          3965:            save_expr_regs = gen_rtx (EXPR_LIST, VOIDmode, temp,
        !          3966:                                      save_expr_regs);
        !          3967: 
        !          3968:          /* If the mode of TEMP does not match that of the expression, it
        !          3969:             must be a promoted value.  We pass store_expr a SUBREG of the
        !          3970:             wanted mode but mark it so that we know that it was already
        !          3971:             extended.  Note that `unsignedp' was modified above in
        !          3972:             this case.  */
        !          3973: 
        !          3974:          if (GET_CODE (temp) == REG && GET_MODE (temp) != mode)
        !          3975:            {
        !          3976:              temp = gen_rtx (SUBREG, mode, SAVE_EXPR_RTL (exp), 0);
        !          3977:              SUBREG_PROMOTED_VAR_P (temp) = 1;
        !          3978:              SUBREG_PROMOTED_UNSIGNED_P (temp) = unsignedp;
        !          3979:            }
        !          3980: 
        !          3981:          store_expr (TREE_OPERAND (exp, 0), temp, 0);
        !          3982:        }
        !          3983: 
        !          3984:       /* If the mode of SAVE_EXPR_RTL does not match that of the expression, it
        !          3985:         must be a promoted value.  We return a SUBREG of the wanted mode,
        !          3986:         but mark it so that we know that it was already extended. */
        !          3987: 
        !          3988:       if (GET_CODE (SAVE_EXPR_RTL (exp)) == REG
        !          3989:          && GET_MODE (SAVE_EXPR_RTL (exp)) != mode)
        !          3990:        {
        !          3991:          enum machine_mode var_mode = mode;
        !          3992: 
        !          3993:          if (TREE_CODE (type) == INTEGER_TYPE
        !          3994:              || TREE_CODE (type) == ENUMERAL_TYPE
        !          3995:              || TREE_CODE (type) == BOOLEAN_TYPE
        !          3996:              || TREE_CODE (type) == CHAR_TYPE
        !          3997:              || TREE_CODE (type) == REAL_TYPE
        !          3998:              || TREE_CODE (type) == POINTER_TYPE
        !          3999:              || TREE_CODE (type) == OFFSET_TYPE)
        !          4000:            {
        !          4001:              PROMOTE_MODE (var_mode, unsignedp, type);
        !          4002:            }
        !          4003: 
        !          4004:          temp = gen_rtx (SUBREG, mode, SAVE_EXPR_RTL (exp), 0);
        !          4005:          SUBREG_PROMOTED_VAR_P (temp) = 1;
        !          4006:          SUBREG_PROMOTED_UNSIGNED_P (temp) = unsignedp;
        !          4007:          return temp;
        !          4008:        }
        !          4009: 
        !          4010:       return SAVE_EXPR_RTL (exp);
        !          4011: 
        !          4012:     case PLACEHOLDER_EXPR:
        !          4013:       /* If there is an object on the head of the placeholder list,
        !          4014:         see if some object in it's references is of type TYPE.  For
        !          4015:         further information, see tree.def.  */
        !          4016:       if (placeholder_list)
        !          4017:        {
        !          4018:          tree object;
        !          4019:          tree old_list = placeholder_list;
        !          4020: 
        !          4021:          for (object = TREE_PURPOSE (placeholder_list);
        !          4022:               TREE_TYPE (object) != type
        !          4023:               && (TREE_CODE_CLASS (TREE_CODE (object)) == 'r'
        !          4024:                   || TREE_CODE_CLASS (TREE_CODE (object)) == '1'
        !          4025:                   || TREE_CODE_CLASS (TREE_CODE (object)) == '2'
        !          4026:                   || TREE_CODE_CLASS (TREE_CODE (object)) == 'e');
        !          4027:               object = TREE_OPERAND (object, 0))
        !          4028:            ;
        !          4029: 
        !          4030:          if (object && TREE_TYPE (object) == type)
        !          4031:            {
        !          4032:              /* Expand this object skipping the list entries before
        !          4033:                 it was found in case it is also a PLACEHOLDER_EXPR.
        !          4034:                 In that case, we want to translate it using subsequent
        !          4035:                 entries.  */
        !          4036:              placeholder_list = TREE_CHAIN (placeholder_list);
        !          4037:              temp = expand_expr (object, original_target, tmode, modifier);
        !          4038:              placeholder_list = old_list;
        !          4039:              return temp;
        !          4040:            }
        !          4041:        }
        !          4042: 
        !          4043:       /* We can't find the object or there was a missing WITH_RECORD_EXPR.  */
        !          4044:       abort ();
        !          4045: 
        !          4046:     case WITH_RECORD_EXPR:
        !          4047:       /* Put the object on the placeholder list, expand our first operand,
        !          4048:         and pop the list.  */
        !          4049:       placeholder_list = tree_cons (TREE_OPERAND (exp, 1), NULL_TREE,
        !          4050:                                    placeholder_list);
        !          4051:       target = expand_expr (TREE_OPERAND (exp, 0), original_target,
        !          4052:                            tmode, modifier);
        !          4053:       placeholder_list = TREE_CHAIN (placeholder_list);
        !          4054:       return target;
        !          4055: 
        !          4056:     case EXIT_EXPR:
        !          4057:       expand_exit_loop_if_false (NULL_PTR,
        !          4058:                                 invert_truthvalue (TREE_OPERAND (exp, 0)));
        !          4059:       return const0_rtx;
        !          4060: 
        !          4061:     case LOOP_EXPR:
        !          4062:       push_temp_slots ();
        !          4063:       expand_start_loop (1);
        !          4064:       expand_expr_stmt (TREE_OPERAND (exp, 0));
        !          4065:       expand_end_loop ();
        !          4066:       pop_temp_slots ();
        !          4067: 
        !          4068:       return const0_rtx;
        !          4069: 
        !          4070:     case BIND_EXPR:
        !          4071:       {
        !          4072:        tree vars = TREE_OPERAND (exp, 0);
        !          4073:        int vars_need_expansion = 0;
        !          4074: 
        !          4075:        /* Need to open a binding contour here because
        !          4076:           if there are any cleanups they most be contained here.  */
        !          4077:        expand_start_bindings (0);
        !          4078: 
        !          4079:        /* Mark the corresponding BLOCK for output in its proper place.  */
        !          4080:        if (TREE_OPERAND (exp, 2) != 0
        !          4081:            && ! TREE_USED (TREE_OPERAND (exp, 2)))
        !          4082:          insert_block (TREE_OPERAND (exp, 2));
        !          4083: 
        !          4084:        /* If VARS have not yet been expanded, expand them now.  */
        !          4085:        while (vars)
        !          4086:          {
        !          4087:            if (DECL_RTL (vars) == 0)
        !          4088:              {
        !          4089:                vars_need_expansion = 1;
        !          4090:                expand_decl (vars);
        !          4091:              }
        !          4092:            expand_decl_init (vars);
        !          4093:            vars = TREE_CHAIN (vars);
        !          4094:          }
        !          4095: 
        !          4096:        temp = expand_expr (TREE_OPERAND (exp, 1), target, tmode, modifier);
        !          4097: 
        !          4098:        expand_end_bindings (TREE_OPERAND (exp, 0), 0, 0);
        !          4099: 
        !          4100:        return temp;
        !          4101:       }
        !          4102: 
        !          4103:     case RTL_EXPR:
        !          4104:       if (RTL_EXPR_SEQUENCE (exp) == const0_rtx)
        !          4105:        abort ();
        !          4106:       emit_insns (RTL_EXPR_SEQUENCE (exp));
        !          4107:       RTL_EXPR_SEQUENCE (exp) = const0_rtx;
        !          4108:       free_temps_for_rtl_expr (exp);
        !          4109:       return RTL_EXPR_RTL (exp);
        !          4110: 
        !          4111:     case CONSTRUCTOR:
        !          4112:       /* If we don't need the result, just ensure we evaluate any
        !          4113:         subexpressions.  */
        !          4114:       if (ignore)
        !          4115:        {
        !          4116:          tree elt;
        !          4117:          for (elt = CONSTRUCTOR_ELTS (exp); elt; elt = TREE_CHAIN (elt))
        !          4118:            expand_expr (TREE_VALUE (elt), const0_rtx, VOIDmode, 0);
        !          4119:          return const0_rtx;
        !          4120:        }
        !          4121:       /* All elts simple constants => refer to a constant in memory.  But
        !          4122:         if this is a non-BLKmode mode, let it store a field at a time
        !          4123:         since that should make a CONST_INT or CONST_DOUBLE when we
        !          4124:         fold.  If we are making an initializer and all operands are
        !          4125:         constant, put it in memory as well.  */
        !          4126:       else if ((TREE_STATIC (exp)
        !          4127:                && (mode == BLKmode || TREE_ADDRESSABLE (exp)))
        !          4128:               || (modifier == EXPAND_INITIALIZER && TREE_CONSTANT (exp)))
        !          4129:        {
        !          4130:          rtx constructor = output_constant_def (exp);
        !          4131:          if (modifier != EXPAND_CONST_ADDRESS
        !          4132:              && modifier != EXPAND_INITIALIZER
        !          4133:              && modifier != EXPAND_SUM
        !          4134:              && !memory_address_p (GET_MODE (constructor),
        !          4135:                                    XEXP (constructor, 0)))
        !          4136:            constructor = change_address (constructor, VOIDmode,
        !          4137:                                          XEXP (constructor, 0));
        !          4138:          return constructor;
        !          4139:        }
        !          4140: 
        !          4141:       else
        !          4142:        {
        !          4143:          if (target == 0 || ! safe_from_p (target, exp))
        !          4144:            {
        !          4145:              if (mode != BLKmode && ! TREE_ADDRESSABLE (exp))
        !          4146:                target = gen_reg_rtx (mode);
        !          4147:              else
        !          4148:                {
        !          4149:                  enum tree_code c = TREE_CODE (type);
        !          4150:                  target
        !          4151:                    = assign_stack_temp (mode, int_size_in_bytes (type), 0);
        !          4152:                  if (c == RECORD_TYPE || c == UNION_TYPE
        !          4153:                      || c == QUAL_UNION_TYPE || c == ARRAY_TYPE)
        !          4154:                    MEM_IN_STRUCT_P (target) = 1;
        !          4155:                }
        !          4156:            }
        !          4157:          store_constructor (exp, target);
        !          4158:          return target;
        !          4159:        }
        !          4160: 
        !          4161:     case INDIRECT_REF:
        !          4162:       {
        !          4163:        tree exp1 = TREE_OPERAND (exp, 0);
        !          4164:        tree exp2;
        !          4165: 
        !          4166:        /* A SAVE_EXPR as the address in an INDIRECT_EXPR is generated
        !          4167:           for  *PTR += ANYTHING  where PTR is put inside the SAVE_EXPR.
        !          4168:           This code has the same general effect as simply doing
        !          4169:           expand_expr on the save expr, except that the expression PTR
        !          4170:           is computed for use as a memory address.  This means different
        !          4171:           code, suitable for indexing, may be generated.  */
        !          4172:        if (TREE_CODE (exp1) == SAVE_EXPR
        !          4173:            && SAVE_EXPR_RTL (exp1) == 0
        !          4174:            && TREE_CODE (exp2 = TREE_OPERAND (exp1, 0)) != ERROR_MARK
        !          4175:            && TYPE_MODE (TREE_TYPE (exp1)) == Pmode
        !          4176:            && TYPE_MODE (TREE_TYPE (exp2)) == Pmode)
        !          4177:          {
        !          4178:            temp = expand_expr (TREE_OPERAND (exp1, 0), NULL_RTX,
        !          4179:                                VOIDmode, EXPAND_SUM);
        !          4180:            op0 = memory_address (mode, temp);
        !          4181:            op0 = copy_all_regs (op0);
        !          4182:            SAVE_EXPR_RTL (exp1) = op0;
        !          4183:          }
        !          4184:        else
        !          4185:          {
        !          4186:            op0 = expand_expr (exp1, NULL_RTX, VOIDmode, EXPAND_SUM);
        !          4187:            op0 = memory_address (mode, op0);
        !          4188:          }
        !          4189: 
        !          4190:        temp = gen_rtx (MEM, mode, op0);
        !          4191:        /* If address was computed by addition,
        !          4192:           mark this as an element of an aggregate.  */
        !          4193:        if (TREE_CODE (TREE_OPERAND (exp, 0)) == PLUS_EXPR
        !          4194:            || (TREE_CODE (TREE_OPERAND (exp, 0)) == SAVE_EXPR
        !          4195:                && TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) == PLUS_EXPR)
        !          4196:            || TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE
        !          4197:            || TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE
        !          4198:            || TREE_CODE (TREE_TYPE (exp)) == UNION_TYPE
        !          4199:            || TREE_CODE (TREE_TYPE (exp)) == QUAL_UNION_TYPE
        !          4200:            || (TREE_CODE (exp1) == ADDR_EXPR
        !          4201:                && (exp2 = TREE_OPERAND (exp1, 0))
        !          4202:                && (TREE_CODE (TREE_TYPE (exp2)) == ARRAY_TYPE
        !          4203:                    || TREE_CODE (TREE_TYPE (exp2)) == RECORD_TYPE
        !          4204:                    || TREE_CODE (TREE_TYPE (exp2)) == UNION_TYPE
        !          4205:                    || TREE_CODE (TREE_TYPE (exp2)) == QUAL_UNION_TYPE)))
        !          4206:          MEM_IN_STRUCT_P (temp) = 1;
        !          4207:        MEM_VOLATILE_P (temp) = TREE_THIS_VOLATILE (exp) | flag_volatile;
        !          4208: #if 0 /* It is incorrect to set RTX_UNCHANGING_P here, because the fact that
        !          4209:         a location is accessed through a pointer to const does not mean
        !          4210:         that the value there can never change.  */
        !          4211:        RTX_UNCHANGING_P (temp) = TREE_READONLY (exp);
        !          4212: #endif
        !          4213:        return temp;
        !          4214:       }
        !          4215: 
        !          4216:     case ARRAY_REF:
        !          4217:       if (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) != ARRAY_TYPE)
        !          4218:        abort ();
        !          4219: 
        !          4220:       {
        !          4221:        tree array = TREE_OPERAND (exp, 0);
        !          4222:        tree domain = TYPE_DOMAIN (TREE_TYPE (array));
        !          4223:        tree low_bound = domain ? TYPE_MIN_VALUE (domain) : integer_zero_node;
        !          4224:        tree index = TREE_OPERAND (exp, 1);
        !          4225:        tree index_type = TREE_TYPE (index);
        !          4226:        int i;
        !          4227: 
        !          4228:        if (TREE_CODE (low_bound) != INTEGER_CST
        !          4229:            && contains_placeholder_p (low_bound))
        !          4230:          low_bound = build (WITH_RECORD_EXPR, sizetype, low_bound, exp);
        !          4231: 
        !          4232:        /* Optimize the special-case of a zero lower bound.
        !          4233: 
        !          4234:           We convert the low_bound to sizetype to avoid some problems
        !          4235:           with constant folding.  (E.g. suppose the lower bound is 1,
        !          4236:           and its mode is QI.  Without the conversion,  (ARRAY
        !          4237:           +(INDEX-(unsigned char)1)) becomes ((ARRAY+(-(unsigned char)1))
        !          4238:           +INDEX), which becomes (ARRAY+255+INDEX).  Oops!)
        !          4239: 
        !          4240:           But sizetype isn't quite right either (especially if
        !          4241:           the lowbound is negative).  FIXME */
        !          4242: 
        !          4243:        if (! integer_zerop (low_bound))
        !          4244:          index = fold (build (MINUS_EXPR, index_type, index,
        !          4245:                               convert (sizetype, low_bound)));
        !          4246: 
        !          4247:        if (TREE_CODE (index) != INTEGER_CST
        !          4248:            || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
        !          4249:          {
        !          4250:            /* Nonconstant array index or nonconstant element size.
        !          4251:               Generate the tree for *(&array+index) and expand that,
        !          4252:               except do it in a language-independent way
        !          4253:               and don't complain about non-lvalue arrays.
        !          4254:               `mark_addressable' should already have been called
        !          4255:               for any array for which this case will be reached.  */
        !          4256: 
        !          4257:            /* Don't forget the const or volatile flag from the array
        !          4258:               element. */
        !          4259:            tree variant_type = build_type_variant (type,
        !          4260:                                                    TREE_READONLY (exp),
        !          4261:                                                    TREE_THIS_VOLATILE (exp));
        !          4262:            tree array_adr = build1 (ADDR_EXPR,
        !          4263:                                     build_pointer_type (variant_type), array);
        !          4264:            tree elt;
        !          4265:            tree size = size_in_bytes (type);
        !          4266: 
        !          4267:            /* Convert the integer argument to a type the same size as a
        !          4268:               pointer so the multiply won't overflow spuriously.  */
        !          4269:            if (TYPE_PRECISION (index_type) != POINTER_SIZE)
        !          4270:              index = convert (type_for_size (POINTER_SIZE, 0), index);
        !          4271: 
        !          4272:            if (TREE_CODE (size) != INTEGER_CST
        !          4273:                && contains_placeholder_p (size))
        !          4274:              size = build (WITH_RECORD_EXPR, sizetype, size, exp);
        !          4275: 
        !          4276:            /* Don't think the address has side effects
        !          4277:               just because the array does.
        !          4278:               (In some cases the address might have side effects,
        !          4279:               and we fail to record that fact here.  However, it should not
        !          4280:               matter, since expand_expr should not care.)  */
        !          4281:            TREE_SIDE_EFFECTS (array_adr) = 0;
        !          4282: 
        !          4283:            elt = build1 (INDIRECT_REF, type,
        !          4284:                          fold (build (PLUS_EXPR,
        !          4285:                                       TYPE_POINTER_TO (variant_type),
        !          4286:                                       array_adr,
        !          4287:                                       fold (build (MULT_EXPR,
        !          4288:                                                    TYPE_POINTER_TO (variant_type),
        !          4289:                                                    index, size)))));
        !          4290: 
        !          4291:            /* Volatility, etc., of new expression is same as old
        !          4292:               expression.  */
        !          4293:            TREE_SIDE_EFFECTS (elt) = TREE_SIDE_EFFECTS (exp);
        !          4294:            TREE_THIS_VOLATILE (elt) = TREE_THIS_VOLATILE (exp);
        !          4295:            TREE_READONLY (elt) = TREE_READONLY (exp);
        !          4296: 
        !          4297:            return expand_expr (elt, target, tmode, modifier);
        !          4298:          }
        !          4299: 
        !          4300:        /* Fold an expression like: "foo"[2].
        !          4301:           This is not done in fold so it won't happen inside &.  */
        !          4302: 
        !          4303:        if (TREE_CODE (array) == STRING_CST
        !          4304:            && TREE_CODE (index) == INTEGER_CST
        !          4305:            && !TREE_INT_CST_HIGH (index)
        !          4306:            && (i = TREE_INT_CST_LOW (index)) < TREE_STRING_LENGTH (array))
        !          4307:          {
        !          4308:            if (TREE_TYPE (TREE_TYPE (array)) == integer_type_node)
        !          4309:              {
        !          4310:                exp = build_int_2 (((int *)TREE_STRING_POINTER (array))[i], 0);
        !          4311:                TREE_TYPE (exp) = integer_type_node;
        !          4312:                return expand_expr (exp, target, tmode, modifier);
        !          4313:              }
        !          4314:            if (TREE_TYPE (TREE_TYPE (array)) == char_type_node)
        !          4315:              {
        !          4316:                exp = build_int_2 (TREE_STRING_POINTER (array)[i], 0);
        !          4317:                TREE_TYPE (exp) = integer_type_node;
        !          4318:                return expand_expr (convert (TREE_TYPE (TREE_TYPE (array)),
        !          4319:                                             exp),
        !          4320:                                    target, tmode, modifier);
        !          4321:              }
        !          4322:          }
        !          4323: 
        !          4324:        /* If this is a constant index into a constant array,
        !          4325:           just get the value from the array.  Handle both the cases when
        !          4326:           we have an explicit constructor and when our operand is a variable
        !          4327:           that was declared const.  */
        !          4328: 
        !          4329:        if (TREE_CODE (array) == CONSTRUCTOR && ! TREE_SIDE_EFFECTS (array))
        !          4330:          {
        !          4331:            if (TREE_CODE (index) == INTEGER_CST
        !          4332:                && TREE_INT_CST_HIGH (index) == 0)
        !          4333:              {
        !          4334:                tree elem = CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0));
        !          4335: 
        !          4336:                i = TREE_INT_CST_LOW (index);
        !          4337:                while (elem && i--)
        !          4338:                  elem = TREE_CHAIN (elem);
        !          4339:                if (elem)
        !          4340:                  return expand_expr (fold (TREE_VALUE (elem)), target,
        !          4341:                                      tmode, modifier);
        !          4342:              }
        !          4343:          }
        !          4344:          
        !          4345:        else if (optimize >= 1
        !          4346:                 && TREE_READONLY (array) && ! TREE_SIDE_EFFECTS (array)
        !          4347:                 && TREE_CODE (array) == VAR_DECL && DECL_INITIAL (array)
        !          4348:                 && TREE_CODE (DECL_INITIAL (array)) != ERROR_MARK)
        !          4349:          {
        !          4350:            if (TREE_CODE (index) == INTEGER_CST
        !          4351:                && TREE_INT_CST_HIGH (index) == 0)
        !          4352:              {
        !          4353:                tree init = DECL_INITIAL (array);
        !          4354: 
        !          4355:                i = TREE_INT_CST_LOW (index);
        !          4356:                if (TREE_CODE (init) == CONSTRUCTOR)
        !          4357:                  {
        !          4358:                    tree elem = CONSTRUCTOR_ELTS (init);
        !          4359: 
        !          4360:                    while (elem
        !          4361:                           && !tree_int_cst_equal (TREE_PURPOSE (elem), index))
        !          4362:                      elem = TREE_CHAIN (elem);
        !          4363:                    if (elem)
        !          4364:                      return expand_expr (fold (TREE_VALUE (elem)), target,
        !          4365:                                          tmode, modifier);
        !          4366:                  }
        !          4367:                else if (TREE_CODE (init) == STRING_CST
        !          4368:                         && i < TREE_STRING_LENGTH (init))
        !          4369:                  {
        !          4370:                    temp = GEN_INT (TREE_STRING_POINTER (init)[i]);
        !          4371:                    return convert_to_mode (mode, temp, 0);
        !          4372:                  }
        !          4373:              }
        !          4374:          }
        !          4375:       }
        !          4376: 
        !          4377:       /* Treat array-ref with constant index as a component-ref.  */
        !          4378: 
        !          4379:     case COMPONENT_REF:
        !          4380:       /* Treat union-cast as an ordinary cast, i.e. translate
        !          4381:         "((union foo*)X)->elem" into "*(typeof (foo.elem)*)X",
        !          4382:         so that MEM_IN_STRUCT_P will not be set for the resulting rtl. */
        !          4383: 
        !          4384:       if (TREE_CODE (TREE_OPERAND (exp, 0)) == INDIRECT_REF
        !          4385:          && TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == UNION_TYPE
        !          4386:          && TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) == NOP_EXPR)
        !          4387:        {
        !          4388:          tree addr = TREE_OPERAND (TREE_OPERAND (TREE_OPERAND (exp, 0), 0), 0);
        !          4389:          tree casted_type = build_pointer_type (TREE_TYPE (exp));
        !          4390:          tree casted_addr = build1 (NOP_EXPR, casted_type, addr);
        !          4391:          return expand_expr (build1 (INDIRECT_REF, TREE_TYPE (exp), casted_addr),
        !          4392:                              target, tmode, modifier);
        !          4393:        }
        !          4394:       
        !          4395:       /* Treat bit fields and component refs the same */
        !          4396:  
        !          4397:     case BIT_FIELD_REF:
        !          4398:       /* If the operand is a CONSTRUCTOR, we can just extract the
        !          4399:         appropriate field if it is present.  */
        !          4400:       if (code != ARRAY_REF
        !          4401:          && TREE_CODE (TREE_OPERAND (exp, 0)) == CONSTRUCTOR)
        !          4402:        {
        !          4403:          tree elt;
        !          4404: 
        !          4405:          for (elt = CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0)); elt;
        !          4406:               elt = TREE_CHAIN (elt))
        !          4407:            if (TREE_PURPOSE (elt) == TREE_OPERAND (exp, 1))
        !          4408:              return expand_expr (TREE_VALUE (elt), target, tmode, modifier);
        !          4409:        }
        !          4410: 
        !          4411:       {
        !          4412:        enum machine_mode mode1;
        !          4413:        int bitsize;
        !          4414:        int bitpos;
        !          4415:        tree offset;
        !          4416:        int volatilep = 0;
        !          4417:        tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset,
        !          4418:                                        &mode1, &unsignedp, &volatilep);
        !          4419:        int alignment;
        !          4420: 
        !          4421:        /* If we got back the original object, something is wrong.  Perhaps
        !          4422:           we are evaluating an expression too early.  In any event, don't
        !          4423:           infinitely recurse.  */
        !          4424:        if (tem == exp)
        !          4425:          abort ();
        !          4426: 
        !          4427:        /* In some cases, we will be offsetting OP0's address by a constant.
        !          4428:           So get it as a sum, if possible.  If we will be using it
        !          4429:           directly in an insn, we validate it.  */
        !          4430:        op0 = expand_expr (tem, NULL_RTX, VOIDmode, EXPAND_SUM);
        !          4431: 
        !          4432:        /* If this is a constant, put it into a register if it is a
        !          4433:           legitimate constant and memory if it isn't.  */
        !          4434:        if (CONSTANT_P (op0))
        !          4435:          {
        !          4436:            enum machine_mode mode = TYPE_MODE (TREE_TYPE (tem));
        !          4437:            if (mode != BLKmode && LEGITIMATE_CONSTANT_P (op0))
        !          4438:              op0 = force_reg (mode, op0);
        !          4439:            else
        !          4440:              op0 = validize_mem (force_const_mem (mode, op0));
        !          4441:          }
        !          4442: 
        !          4443:        alignment = TYPE_ALIGN (TREE_TYPE (tem)) / BITS_PER_UNIT;
        !          4444:        if (offset != 0)
        !          4445:          {
        !          4446:            rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
        !          4447: 
        !          4448:            if (GET_CODE (op0) != MEM)
        !          4449:              abort ();
        !          4450:            op0 = change_address (op0, VOIDmode,
        !          4451:                                  gen_rtx (PLUS, Pmode, XEXP (op0, 0),
        !          4452:                                           force_reg (Pmode, offset_rtx)));
        !          4453:          /* If we have a variable offset, the known alignment
        !          4454:             is only that of the innermost structure containing the field.
        !          4455:             (Actually, we could sometimes do better by using the
        !          4456:             size of an element of the innermost array, but no need.)  */
        !          4457:          if (TREE_CODE (exp) == COMPONENT_REF
        !          4458:              || TREE_CODE (exp) == BIT_FIELD_REF)
        !          4459:            alignment = (TYPE_ALIGN (TREE_TYPE (TREE_OPERAND (exp, 0)))
        !          4460:                         / BITS_PER_UNIT);
        !          4461:          }
        !          4462: 
        !          4463:        /* Don't forget about volatility even if this is a bitfield.  */
        !          4464:        if (GET_CODE (op0) == MEM && volatilep && ! MEM_VOLATILE_P (op0))
        !          4465:          {
        !          4466:            op0 = copy_rtx (op0);
        !          4467:            MEM_VOLATILE_P (op0) = 1;
        !          4468:          }
        !          4469: 
        !          4470:        /* In cases where an aligned union has an unaligned object
        !          4471:           as a field, we might be extracting a BLKmode value from
        !          4472:           an integer-mode (e.g., SImode) object.  Handle this case
        !          4473:           by doing the extract into an object as wide as the field
        !          4474:           (which we know to be the width of a basic mode), then
        !          4475:           storing into memory, and changing the mode to BLKmode.  */
        !          4476:        if (mode1 == VOIDmode
        !          4477:            || (mode1 != BLKmode && ! direct_load[(int) mode1]
        !          4478:                && modifier != EXPAND_CONST_ADDRESS
        !          4479:                && modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
        !          4480:            || GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
        !          4481:            /* If the field isn't aligned enough to fetch as a memref,
        !          4482:               fetch it as a bit field.  */
        !          4483:            || (STRICT_ALIGNMENT
        !          4484:                && TYPE_ALIGN (TREE_TYPE (tem)) < GET_MODE_ALIGNMENT (mode))
        !          4485:            || (STRICT_ALIGNMENT && bitpos % GET_MODE_ALIGNMENT (mode) != 0))
        !          4486:          {
        !          4487:            enum machine_mode ext_mode = mode;
        !          4488: 
        !          4489:            if (ext_mode == BLKmode)
        !          4490:              ext_mode = mode_for_size (bitsize, MODE_INT, 1);
        !          4491: 
        !          4492:            if (ext_mode == BLKmode)
        !          4493:              abort ();
        !          4494: 
        !          4495:            op0 = extract_bit_field (validize_mem (op0), bitsize, bitpos,
        !          4496:                                     unsignedp, target, ext_mode, ext_mode,
        !          4497:                                     alignment,
        !          4498:                                     int_size_in_bytes (TREE_TYPE (tem)));
        !          4499:            if (mode == BLKmode)
        !          4500:              {
        !          4501:                rtx new = assign_stack_temp (ext_mode,
        !          4502:                                             bitsize / BITS_PER_UNIT, 0);
        !          4503: 
        !          4504:                emit_move_insn (new, op0);
        !          4505:                op0 = copy_rtx (new);
        !          4506:                PUT_MODE (op0, BLKmode);
        !          4507:                MEM_IN_STRUCT_P (op0) = 1;
        !          4508:              }
        !          4509: 
        !          4510:            return op0;
        !          4511:          }
        !          4512: 
        !          4513:        /* Get a reference to just this component.  */
        !          4514:        if (modifier == EXPAND_CONST_ADDRESS
        !          4515:            || modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER)
        !          4516:          op0 = gen_rtx (MEM, mode1, plus_constant (XEXP (op0, 0),
        !          4517:                                                    (bitpos / BITS_PER_UNIT)));
        !          4518:        else
        !          4519:          op0 = change_address (op0, mode1,
        !          4520:                                plus_constant (XEXP (op0, 0),
        !          4521:                                               (bitpos / BITS_PER_UNIT)));
        !          4522:        MEM_IN_STRUCT_P (op0) = 1;
        !          4523:        MEM_VOLATILE_P (op0) |= volatilep;
        !          4524:        if (mode == mode1 || mode1 == BLKmode || mode1 == tmode)
        !          4525:          target = op0;
        !          4526:        else 
        !          4527:          {
        !          4528:            if (target == 0)
        !          4529:              target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
        !          4530:            convert_move (target, op0, unsignedp);
        !          4531:          }
        !          4532:        /*
        !          4533:        if (modifier == EXPAND_NORMAL 
        !          4534:            && TREE_SELF_OFFSET (TREE_OPERAND (exp, 1)))
        !          4535:          {
        !          4536:            rtx op0 = memory_address (mode, XEXP (target, 0));
        !          4537:            rtx op1 = gen_rtx (PLUS, mode, op0, target);
        !          4538:            temp = gen_rtx (MEM, mode, memory_address (mode, op1));
        !          4539:            MEM_IN_STRUCT_P (temp) = 1;
        !          4540:            MEM_VOLATILE_P (temp) = MEM_VOLATILE_P (target);
        !          4541:            return temp;
        !          4542:          }
        !          4543:        else
        !          4544:        */
        !          4545:          return target;
        !          4546:       }
        !          4547: 
        !          4548:     case OFFSET_REF:
        !          4549:       {
        !          4550:        tree base = build1 (ADDR_EXPR, type, TREE_OPERAND (exp, 0));
        !          4551:        tree addr = build (PLUS_EXPR, type, base, TREE_OPERAND (exp, 1));
        !          4552:        op0 = expand_expr (addr, NULL_RTX, VOIDmode, EXPAND_SUM);
        !          4553:        temp = gen_rtx (MEM, mode, memory_address (mode, op0));
        !          4554:        MEM_IN_STRUCT_P (temp) = 1;
        !          4555:        MEM_VOLATILE_P (temp) = TREE_THIS_VOLATILE (exp);
        !          4556: #if 0 /* It is incorrect to set RTX_UNCHANGING_P here, because the fact that
        !          4557:         a location is accessed through a pointer to const does not mean
        !          4558:         that the value there can never change.  */
        !          4559:        RTX_UNCHANGING_P (temp) = TREE_READONLY (exp);
        !          4560: #endif
        !          4561:        return temp;
        !          4562:       }
        !          4563: 
        !          4564:       /* Intended for a reference to a buffer of a file-object in Pascal.
        !          4565:         But it's not certain that a special tree code will really be
        !          4566:         necessary for these.  INDIRECT_REF might work for them.  */
        !          4567:     case BUFFER_REF:
        !          4568:       abort ();
        !          4569: 
        !          4570:     /* IN_EXPR: Inlined pascal set IN expression.
        !          4571: 
        !          4572:        Algorithm:
        !          4573:          rlo       = set_low - (set_low%bits_per_word);
        !          4574:         the_word  = set [ (index - rlo)/bits_per_word ];
        !          4575:         bit_index = index % bits_per_word;
        !          4576:         bitmask   = 1 << bit_index;
        !          4577:         return !!(the_word & bitmask);  */
        !          4578:     case IN_EXPR:
        !          4579:       preexpand_calls (exp);
        !          4580:       {
        !          4581:        tree set = TREE_OPERAND (exp, 0);
        !          4582:        tree index = TREE_OPERAND (exp, 1);
        !          4583:        tree set_type = TREE_TYPE (set);
        !          4584: 
        !          4585:        tree set_low_bound = TYPE_MIN_VALUE (TYPE_DOMAIN (set_type));
        !          4586:        tree set_high_bound = TYPE_MAX_VALUE (TYPE_DOMAIN (set_type));
        !          4587: 
        !          4588:        rtx index_val;
        !          4589:        rtx lo_r;
        !          4590:        rtx hi_r;
        !          4591:        rtx rlow;
        !          4592:        rtx diff, quo, rem, addr, bit, result;
        !          4593:        rtx setval, setaddr;
        !          4594:        enum machine_mode index_mode = TYPE_MODE (TREE_TYPE (index));
        !          4595: 
        !          4596:        if (target == 0)
        !          4597:          target = gen_reg_rtx (mode);
        !          4598: 
        !          4599:        /* If domain is empty, answer is no.  */
        !          4600:        if (tree_int_cst_lt (set_high_bound, set_low_bound))
        !          4601:          return const0_rtx;
        !          4602: 
        !          4603:        index_val = expand_expr (index, 0, VOIDmode, 0);
        !          4604:        lo_r = expand_expr (set_low_bound, 0, VOIDmode, 0);
        !          4605:        hi_r = expand_expr (set_high_bound, 0, VOIDmode, 0);
        !          4606:        setval = expand_expr (set, 0, VOIDmode, 0);
        !          4607:        setaddr = XEXP (setval, 0); 
        !          4608: 
        !          4609:        /* Compare index against bounds, if they are constant.  */
        !          4610:        if (GET_CODE (index_val) == CONST_INT
        !          4611:            && GET_CODE (lo_r) == CONST_INT
        !          4612:            && INTVAL (index_val) < INTVAL (lo_r))
        !          4613:          return const0_rtx;
        !          4614: 
        !          4615:        if (GET_CODE (index_val) == CONST_INT
        !          4616:            && GET_CODE (hi_r) == CONST_INT
        !          4617:            && INTVAL (hi_r) < INTVAL (index_val))
        !          4618:          return const0_rtx;
        !          4619: 
        !          4620:        /* If we get here, we have to generate the code for both cases
        !          4621:           (in range and out of range).  */
        !          4622: 
        !          4623:        op0 = gen_label_rtx ();
        !          4624:        op1 = gen_label_rtx ();
        !          4625: 
        !          4626:        if (! (GET_CODE (index_val) == CONST_INT
        !          4627:               && GET_CODE (lo_r) == CONST_INT))
        !          4628:          {
        !          4629:            emit_cmp_insn (index_val, lo_r, LT, NULL_RTX,
        !          4630:                           GET_MODE (index_val), 0, 0);
        !          4631:            emit_jump_insn (gen_blt (op1));
        !          4632:          }
        !          4633: 
        !          4634:        if (! (GET_CODE (index_val) == CONST_INT
        !          4635:               && GET_CODE (hi_r) == CONST_INT))
        !          4636:          {
        !          4637:            emit_cmp_insn (index_val, hi_r, GT, NULL_RTX,
        !          4638:                           GET_MODE (index_val), 0, 0);
        !          4639:            emit_jump_insn (gen_bgt (op1));
        !          4640:          }
        !          4641: 
        !          4642:        /* Calculate the element number of bit zero in the first word
        !          4643:           of the set.  */
        !          4644:        if (GET_CODE (lo_r) == CONST_INT)
        !          4645:          rlow = GEN_INT (INTVAL (lo_r)
        !          4646:                          & ~ ((HOST_WIDE_INT) 1 << BITS_PER_UNIT));
        !          4647:        else
        !          4648:          rlow = expand_binop (index_mode, and_optab, lo_r,
        !          4649:                               GEN_INT (~((HOST_WIDE_INT) 1 << BITS_PER_UNIT)),
        !          4650:                               NULL_RTX, 0, OPTAB_LIB_WIDEN);
        !          4651: 
        !          4652:        diff = expand_binop (index_mode, sub_optab,
        !          4653:                             index_val, rlow, NULL_RTX, 0, OPTAB_LIB_WIDEN);
        !          4654: 
        !          4655:        quo = expand_divmod (0, TRUNC_DIV_EXPR, index_mode, diff,
        !          4656:                             GEN_INT (BITS_PER_UNIT), NULL_RTX, 0);
        !          4657:        rem = expand_divmod (1, TRUNC_MOD_EXPR, index_mode, index_val,
        !          4658:                             GEN_INT (BITS_PER_UNIT), NULL_RTX, 0);
        !          4659:        addr = memory_address (byte_mode,
        !          4660:                               expand_binop (index_mode, add_optab,
        !          4661:                                             diff, setaddr, NULL_RTX, 0,
        !          4662:                                             OPTAB_LIB_WIDEN));
        !          4663:        /* Extract the bit we want to examine */
        !          4664:        bit = expand_shift (RSHIFT_EXPR, byte_mode,
        !          4665:                            gen_rtx (MEM, byte_mode, addr),
        !          4666:                            make_tree (TREE_TYPE (index), rem),
        !          4667:                            NULL_RTX, 1);
        !          4668:        result = expand_binop (byte_mode, and_optab, bit, const1_rtx,
        !          4669:                               GET_MODE (target) == byte_mode ? target : 0,
        !          4670:                               1, OPTAB_LIB_WIDEN);
        !          4671: 
        !          4672:        if (result != target)
        !          4673:          convert_move (target, result, 1);
        !          4674: 
        !          4675:        /* Output the code to handle the out-of-range case.  */
        !          4676:        emit_jump (op0);
        !          4677:        emit_label (op1);
        !          4678:        emit_move_insn (target, const0_rtx);
        !          4679:        emit_label (op0);
        !          4680:        return target;
        !          4681:       }
        !          4682: 
        !          4683:     case WITH_CLEANUP_EXPR:
        !          4684:       if (RTL_EXPR_RTL (exp) == 0)
        !          4685:        {
        !          4686:          RTL_EXPR_RTL (exp)
        !          4687:            = expand_expr (TREE_OPERAND (exp, 0),
        !          4688:                           target ? target : const0_rtx,
        !          4689:                           tmode, modifier);
        !          4690:          cleanups_this_call
        !          4691:            = tree_cons (NULL_TREE, TREE_OPERAND (exp, 2), cleanups_this_call);
        !          4692:          /* That's it for this cleanup.  */
        !          4693:          TREE_OPERAND (exp, 2) = 0;
        !          4694:        }
        !          4695:       return RTL_EXPR_RTL (exp);
        !          4696: 
        !          4697:     case CALL_EXPR:
        !          4698:       /* Check for a built-in function.  */
        !          4699:       if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
        !          4700:          && TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) == FUNCTION_DECL
        !          4701:          && DECL_BUILT_IN (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
        !          4702:        return expand_builtin (exp, target, subtarget, tmode, ignore);
        !          4703:       /* If this call was expanded already by preexpand_calls,
        !          4704:         just return the result we got.  */
        !          4705:       if (CALL_EXPR_RTL (exp) != 0)
        !          4706:        return CALL_EXPR_RTL (exp);
        !          4707:       return expand_call (exp, target, ignore);
        !          4708: 
        !          4709:     case NON_LVALUE_EXPR:
        !          4710:     case NOP_EXPR:
        !          4711:     case CONVERT_EXPR:
        !          4712:     case REFERENCE_EXPR:
        !          4713:       if (mode == TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
        !          4714:        return expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, modifier);
        !          4715:       if (TREE_CODE (type) == UNION_TYPE)
        !          4716:        {
        !          4717:          tree valtype = TREE_TYPE (TREE_OPERAND (exp, 0));
        !          4718:          if (target == 0)
        !          4719:            {
        !          4720:              if (mode == BLKmode)
        !          4721:                {
        !          4722:                  if (TYPE_SIZE (type) == 0
        !          4723:                      || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
        !          4724:                    abort ();
        !          4725:                  target = assign_stack_temp (BLKmode,
        !          4726:                                              (TREE_INT_CST_LOW (TYPE_SIZE (type))
        !          4727:                                               + BITS_PER_UNIT - 1)
        !          4728:                                              / BITS_PER_UNIT, 0);
        !          4729:                }
        !          4730:              else
        !          4731:                target = gen_reg_rtx (mode);
        !          4732:            }
        !          4733:          if (GET_CODE (target) == MEM)
        !          4734:            /* Store data into beginning of memory target.  */
        !          4735:            store_expr (TREE_OPERAND (exp, 0),
        !          4736:                        change_address (target, TYPE_MODE (valtype), 0), 0);
        !          4737: 
        !          4738:          else if (GET_CODE (target) == REG)
        !          4739:            /* Store this field into a union of the proper type.  */
        !          4740:            store_field (target, GET_MODE_BITSIZE (TYPE_MODE (valtype)), 0,
        !          4741:                         TYPE_MODE (valtype), TREE_OPERAND (exp, 0),
        !          4742:                         VOIDmode, 0, 1,
        !          4743:                         int_size_in_bytes (TREE_TYPE (TREE_OPERAND (exp, 0))));
        !          4744:          else
        !          4745:            abort ();
        !          4746: 
        !          4747:          /* Return the entire union.  */
        !          4748:          return target;
        !          4749:        }
        !          4750:       op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, mode, 0);
        !          4751:       if (GET_MODE (op0) == mode)
        !          4752:        return op0;
        !          4753:       /* If arg is a constant integer being extended from a narrower mode,
        !          4754:         we must really truncate to get the extended bits right.  Otherwise
        !          4755:         (unsigned long) (unsigned char) ("\377"[0])
        !          4756:         would come out as ffffffff.  */
        !          4757:       if (GET_MODE (op0) == VOIDmode
        !          4758:          && (GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
        !          4759:              < GET_MODE_BITSIZE (mode)))
        !          4760:        {
        !          4761:          /* MODE must be narrower than HOST_BITS_PER_INT.  */
        !          4762:          int width = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))));
        !          4763: 
        !          4764:          if (width < HOST_BITS_PER_WIDE_INT)
        !          4765:            {
        !          4766:              HOST_WIDE_INT val = (GET_CODE (op0) == CONST_INT ? INTVAL (op0)
        !          4767:                                   : CONST_DOUBLE_LOW (op0));
        !          4768:              if (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0)))
        !          4769:                  || !(val & ((HOST_WIDE_INT) 1 << (width - 1))))
        !          4770:                val &= ((HOST_WIDE_INT) 1 << width) - 1;
        !          4771:              else
        !          4772:                val |= ~(((HOST_WIDE_INT) 1 << width) - 1);
        !          4773: 
        !          4774:              op0 = GEN_INT (val);
        !          4775:            }
        !          4776:          else
        !          4777:            {
        !          4778:              op0 = (simplify_unary_operation
        !          4779:                     ((TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0)))
        !          4780:                       ? ZERO_EXTEND : SIGN_EXTEND),
        !          4781:                      mode, op0,
        !          4782:                      TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))));
        !          4783:              if (op0 == 0)
        !          4784:                abort ();
        !          4785:            }
        !          4786:        }
        !          4787:       if (GET_MODE (op0) == VOIDmode)
        !          4788:        return op0;
        !          4789:       if (modifier == EXPAND_INITIALIZER)
        !          4790:        return gen_rtx (unsignedp ? ZERO_EXTEND : SIGN_EXTEND, mode, op0);
        !          4791:       if (flag_force_mem && GET_CODE (op0) == MEM)
        !          4792:        op0 = copy_to_reg (op0);
        !          4793: 
        !          4794:       if (target == 0)
        !          4795:        return convert_to_mode (mode, op0, TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
        !          4796:       else
        !          4797:        convert_move (target, op0, TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
        !          4798:       return target;
        !          4799: 
        !          4800:     case PLUS_EXPR:
        !          4801:       /* We come here from MINUS_EXPR when the second operand is a constant. */
        !          4802:     plus_expr:
        !          4803:       this_optab = add_optab;
        !          4804: 
        !          4805:       /* If we are adding a constant, an RTL_EXPR that is sp, fp, or ap, and
        !          4806:         something else, make sure we add the register to the constant and
        !          4807:         then to the other thing.  This case can occur during strength
        !          4808:         reduction and doing it this way will produce better code if the
        !          4809:         frame pointer or argument pointer is eliminated.
        !          4810: 
        !          4811:         fold-const.c will ensure that the constant is always in the inner
        !          4812:         PLUS_EXPR, so the only case we need to do anything about is if
        !          4813:         sp, ap, or fp is our second argument, in which case we must swap
        !          4814:         the innermost first argument and our second argument.  */
        !          4815: 
        !          4816:       if (TREE_CODE (TREE_OPERAND (exp, 0)) == PLUS_EXPR
        !          4817:          && TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 1)) == INTEGER_CST
        !          4818:          && TREE_CODE (TREE_OPERAND (exp, 1)) == RTL_EXPR
        !          4819:          && (RTL_EXPR_RTL (TREE_OPERAND (exp, 1)) == frame_pointer_rtx
        !          4820:              || RTL_EXPR_RTL (TREE_OPERAND (exp, 1)) == stack_pointer_rtx
        !          4821:              || RTL_EXPR_RTL (TREE_OPERAND (exp, 1)) == arg_pointer_rtx))
        !          4822:        {
        !          4823:          tree t = TREE_OPERAND (exp, 1);
        !          4824: 
        !          4825:          TREE_OPERAND (exp, 1) = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
        !          4826:          TREE_OPERAND (TREE_OPERAND (exp, 0), 0) = t;
        !          4827:        }
        !          4828: 
        !          4829:       /* If the result is to be Pmode and we are adding an integer to
        !          4830:         something, we might be forming a constant.  So try to use
        !          4831:         plus_constant.  If it produces a sum and we can't accept it,
        !          4832:         use force_operand.  This allows P = &ARR[const] to generate
        !          4833:         efficient code on machines where a SYMBOL_REF is not a valid
        !          4834:         address.
        !          4835: 
        !          4836:         If this is an EXPAND_SUM call, always return the sum.  */
        !          4837:       if (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER
        !          4838:          || mode == Pmode)
        !          4839:        {
        !          4840:          if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST
        !          4841:              && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
        !          4842:              && TREE_CONSTANT (TREE_OPERAND (exp, 1)))
        !          4843:            {
        !          4844:              op1 = expand_expr (TREE_OPERAND (exp, 1), subtarget, VOIDmode,
        !          4845:                                 EXPAND_SUM);
        !          4846:              op1 = plus_constant (op1, TREE_INT_CST_LOW (TREE_OPERAND (exp, 0)));
        !          4847:              if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
        !          4848:                op1 = force_operand (op1, target);
        !          4849:              return op1;
        !          4850:            }
        !          4851: 
        !          4852:          else if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
        !          4853:                   && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_INT
        !          4854:                   && TREE_CONSTANT (TREE_OPERAND (exp, 0)))
        !          4855:            {
        !          4856:              op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode,
        !          4857:                                 EXPAND_SUM);
        !          4858:              if (! CONSTANT_P (op0))
        !          4859:                {
        !          4860:                  op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX,
        !          4861:                                     VOIDmode, modifier);
        !          4862:                  /* Don't go to both_summands if modifier
        !          4863:                     says it's not right to return a PLUS.  */
        !          4864:                  if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
        !          4865:                    goto binop2;
        !          4866:                  goto both_summands;
        !          4867:                }
        !          4868:              op0 = plus_constant (op0, TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)));
        !          4869:              if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
        !          4870:                op0 = force_operand (op0, target);
        !          4871:              return op0;
        !          4872:            }
        !          4873:        }
        !          4874: 
        !          4875:       /* No sense saving up arithmetic to be done
        !          4876:         if it's all in the wrong mode to form part of an address.
        !          4877:         And force_operand won't know whether to sign-extend or
        !          4878:         zero-extend.  */
        !          4879:       if ((modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
        !          4880:          || mode != Pmode)
        !          4881:        goto binop;
        !          4882: 
        !          4883:       preexpand_calls (exp);
        !          4884:       if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1)))
        !          4885:        subtarget = 0;
        !          4886: 
        !          4887:       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, modifier);
        !          4888:       op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, modifier);
        !          4889: 
        !          4890:     both_summands:
        !          4891:       /* Make sure any term that's a sum with a constant comes last.  */
        !          4892:       if (GET_CODE (op0) == PLUS
        !          4893:          && CONSTANT_P (XEXP (op0, 1)))
        !          4894:        {
        !          4895:          temp = op0;
        !          4896:          op0 = op1;
        !          4897:          op1 = temp;
        !          4898:        }
        !          4899:       /* If adding to a sum including a constant,
        !          4900:         associate it to put the constant outside.  */
        !          4901:       if (GET_CODE (op1) == PLUS
        !          4902:          && CONSTANT_P (XEXP (op1, 1)))
        !          4903:        {
        !          4904:          rtx constant_term = const0_rtx;
        !          4905: 
        !          4906:          temp = simplify_binary_operation (PLUS, mode, XEXP (op1, 0), op0);
        !          4907:          if (temp != 0)
        !          4908:            op0 = temp;
        !          4909:          /* Ensure that MULT comes first if there is one.  */
        !          4910:          else if (GET_CODE (op0) == MULT)
        !          4911:            op0 = gen_rtx (PLUS, mode, op0, XEXP (op1, 0));
        !          4912:          else
        !          4913:            op0 = gen_rtx (PLUS, mode, XEXP (op1, 0), op0);
        !          4914: 
        !          4915:          /* Let's also eliminate constants from op0 if possible.  */
        !          4916:          op0 = eliminate_constant_term (op0, &constant_term);
        !          4917: 
        !          4918:          /* CONSTANT_TERM and XEXP (op1, 1) are known to be constant, so
        !          4919:             their sum should be a constant.  Form it into OP1, since the 
        !          4920:             result we want will then be OP0 + OP1.  */
        !          4921: 
        !          4922:          temp = simplify_binary_operation (PLUS, mode, constant_term,
        !          4923:                                            XEXP (op1, 1));
        !          4924:          if (temp != 0)
        !          4925:            op1 = temp;
        !          4926:          else
        !          4927:            op1 = gen_rtx (PLUS, mode, constant_term, XEXP (op1, 1));
        !          4928:        }
        !          4929: 
        !          4930:       /* Put a constant term last and put a multiplication first.  */
        !          4931:       if (CONSTANT_P (op0) || GET_CODE (op1) == MULT)
        !          4932:        temp = op1, op1 = op0, op0 = temp;
        !          4933: 
        !          4934:       temp = simplify_binary_operation (PLUS, mode, op0, op1);
        !          4935:       return temp ? temp : gen_rtx (PLUS, mode, op0, op1);
        !          4936: 
        !          4937:     case MINUS_EXPR:
        !          4938:       /* For initializers, we are allowed to return a MINUS of two
        !          4939:         symbolic constants.  Here we handle all cases when both operands
        !          4940:         are constant.  */
        !          4941:       /* Handle difference of two symbolic constants,
        !          4942:         for the sake of an initializer.  */
        !          4943:       if ((modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER)
        !          4944:          && really_constant_p (TREE_OPERAND (exp, 0))
        !          4945:          && really_constant_p (TREE_OPERAND (exp, 1)))
        !          4946:        {
        !          4947:          rtx op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX,
        !          4948:                                 VOIDmode, modifier);
        !          4949:          rtx op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX,
        !          4950:                                 VOIDmode, modifier);
        !          4951: 
        !          4952:          /* If one operand is a CONST_INT, put it last.  */
        !          4953:          if (GET_CODE (op0) == CONST_INT)
        !          4954:            temp = op0, op0 = op1, op1 = temp;
        !          4955: 
        !          4956:          /* If the last operand is a CONST_INT, use plus_constant of
        !          4957:             the negated constant.  Else make the MINUS.  */
        !          4958:          if (GET_CODE (op1) == CONST_INT)
        !          4959:            return plus_constant (op0, - INTVAL (op1));
        !          4960:          else
        !          4961:            return gen_rtx (MINUS, mode, op0, op1);
        !          4962:        }
        !          4963:       /* Convert A - const to A + (-const).  */
        !          4964:       if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
        !          4965:        {
        !          4966:          exp = build (PLUS_EXPR, type, TREE_OPERAND (exp, 0),
        !          4967:                       fold (build1 (NEGATE_EXPR, type,
        !          4968:                                     TREE_OPERAND (exp, 1))));
        !          4969:          goto plus_expr;
        !          4970:        }
        !          4971:       this_optab = sub_optab;
        !          4972:       goto binop;
        !          4973: 
        !          4974:     case MULT_EXPR:
        !          4975:       preexpand_calls (exp);
        !          4976:       /* If first operand is constant, swap them.
        !          4977:         Thus the following special case checks need only
        !          4978:         check the second operand.  */
        !          4979:       if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST)
        !          4980:        {
        !          4981:          register tree t1 = TREE_OPERAND (exp, 0);
        !          4982:          TREE_OPERAND (exp, 0) = TREE_OPERAND (exp, 1);
        !          4983:          TREE_OPERAND (exp, 1) = t1;
        !          4984:        }
        !          4985: 
        !          4986:       /* Attempt to return something suitable for generating an
        !          4987:         indexed address, for machines that support that.  */
        !          4988: 
        !          4989:       if (modifier == EXPAND_SUM && mode == Pmode
        !          4990:          && TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
        !          4991:          && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
        !          4992:        {
        !          4993:          op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, EXPAND_SUM);
        !          4994: 
        !          4995:          /* Apply distributive law if OP0 is x+c.  */
        !          4996:          if (GET_CODE (op0) == PLUS
        !          4997:              && GET_CODE (XEXP (op0, 1)) == CONST_INT)
        !          4998:            return gen_rtx (PLUS, mode,
        !          4999:                            gen_rtx (MULT, mode, XEXP (op0, 0),
        !          5000:                                     GEN_INT (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)))),
        !          5001:                            GEN_INT (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1))
        !          5002:                                     * INTVAL (XEXP (op0, 1))));
        !          5003: 
        !          5004:          if (GET_CODE (op0) != REG)
        !          5005:            op0 = force_operand (op0, NULL_RTX);
        !          5006:          if (GET_CODE (op0) != REG)
        !          5007:            op0 = copy_to_mode_reg (mode, op0);
        !          5008: 
        !          5009:          return gen_rtx (MULT, mode, op0,
        !          5010:                          GEN_INT (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1))));
        !          5011:        }
        !          5012: 
        !          5013:       if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1)))
        !          5014:        subtarget = 0;
        !          5015: 
        !          5016:       /* Check for multiplying things that have been extended
        !          5017:         from a narrower type.  If this machine supports multiplying
        !          5018:         in that narrower type with a result in the desired type,
        !          5019:         do it that way, and avoid the explicit type-conversion.  */
        !          5020:       if (TREE_CODE (TREE_OPERAND (exp, 0)) == NOP_EXPR
        !          5021:          && TREE_CODE (type) == INTEGER_TYPE
        !          5022:          && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
        !          5023:              < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0))))
        !          5024:          && ((TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
        !          5025:               && int_fits_type_p (TREE_OPERAND (exp, 1),
        !          5026:                                   TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
        !          5027:               /* Don't use a widening multiply if a shift will do.  */
        !          5028:               && ((GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 1))))
        !          5029:                    > HOST_BITS_PER_WIDE_INT)
        !          5030:                   || exact_log2 (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1))) < 0))
        !          5031:              ||
        !          5032:              (TREE_CODE (TREE_OPERAND (exp, 1)) == NOP_EXPR
        !          5033:               && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 1), 0)))
        !          5034:                   ==
        !          5035:                   TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))))
        !          5036:               /* If both operands are extended, they must either both
        !          5037:                  be zero-extended or both be sign-extended.  */
        !          5038:               && (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 1), 0)))
        !          5039:                   ==
        !          5040:                   TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))))))
        !          5041:        {
        !          5042:          enum machine_mode innermode
        !          5043:            = TYPE_MODE (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)));
        !          5044:          this_optab = (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
        !          5045:                        ? umul_widen_optab : smul_widen_optab);
        !          5046:          if (mode == GET_MODE_WIDER_MODE (innermode)
        !          5047:              && this_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
        !          5048:            {
        !          5049:              op0 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
        !          5050:                                 NULL_RTX, VOIDmode, 0);
        !          5051:              if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
        !          5052:                op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX,
        !          5053:                                   VOIDmode, 0);
        !          5054:              else
        !          5055:                op1 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 1), 0),
        !          5056:                                   NULL_RTX, VOIDmode, 0);
        !          5057:              goto binop2;
        !          5058:            }
        !          5059:        }
        !          5060:       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
        !          5061:       op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
        !          5062:       return expand_mult (mode, op0, op1, target, unsignedp);
        !          5063: 
        !          5064:     case TRUNC_DIV_EXPR:
        !          5065:     case FLOOR_DIV_EXPR:
        !          5066:     case CEIL_DIV_EXPR:
        !          5067:     case ROUND_DIV_EXPR:
        !          5068:     case EXACT_DIV_EXPR:
        !          5069:       preexpand_calls (exp);
        !          5070:       if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1)))
        !          5071:        subtarget = 0;
        !          5072:       /* Possible optimization: compute the dividend with EXPAND_SUM
        !          5073:         then if the divisor is constant can optimize the case
        !          5074:         where some terms of the dividend have coeffs divisible by it.  */
        !          5075:       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
        !          5076:       op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
        !          5077:       return expand_divmod (0, code, mode, op0, op1, target, unsignedp);
        !          5078: 
        !          5079:     case RDIV_EXPR:
        !          5080:       this_optab = flodiv_optab;
        !          5081:       goto binop;
        !          5082: 
        !          5083:     case TRUNC_MOD_EXPR:
        !          5084:     case FLOOR_MOD_EXPR:
        !          5085:     case CEIL_MOD_EXPR:
        !          5086:     case ROUND_MOD_EXPR:
        !          5087:       preexpand_calls (exp);
        !          5088:       if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1)))
        !          5089:        subtarget = 0;
        !          5090:       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
        !          5091:       op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
        !          5092:       return expand_divmod (1, code, mode, op0, op1, target, unsignedp);
        !          5093: 
        !          5094:     case FIX_ROUND_EXPR:
        !          5095:     case FIX_FLOOR_EXPR:
        !          5096:     case FIX_CEIL_EXPR:
        !          5097:       abort ();                        /* Not used for C.  */
        !          5098: 
        !          5099:     case FIX_TRUNC_EXPR:
        !          5100:       op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
        !          5101:       if (target == 0)
        !          5102:        target = gen_reg_rtx (mode);
        !          5103:       expand_fix (target, op0, unsignedp);
        !          5104:       return target;
        !          5105: 
        !          5106:     case FLOAT_EXPR:
        !          5107:       op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
        !          5108:       if (target == 0)
        !          5109:        target = gen_reg_rtx (mode);
        !          5110:       /* expand_float can't figure out what to do if FROM has VOIDmode.
        !          5111:         So give it the correct mode.  With -O, cse will optimize this.  */
        !          5112:       if (GET_MODE (op0) == VOIDmode)
        !          5113:        op0 = copy_to_mode_reg (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))),
        !          5114:                                op0);
        !          5115:       expand_float (target, op0,
        !          5116:                    TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
        !          5117:       return target;
        !          5118: 
        !          5119:     case NEGATE_EXPR:
        !          5120:       op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0);
        !          5121:       temp = expand_unop (mode, neg_optab, op0, target, 0);
        !          5122:       if (temp == 0)
        !          5123:        abort ();
        !          5124:       return temp;
        !          5125: 
        !          5126:     case ABS_EXPR:
        !          5127:       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
        !          5128: 
        !          5129:       /* Handle complex values specially.  */
        !          5130:       {
        !          5131:        enum machine_mode opmode
        !          5132:          = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
        !          5133: 
        !          5134:        if (GET_MODE_CLASS (opmode) == MODE_COMPLEX_INT
        !          5135:            || GET_MODE_CLASS (opmode) == MODE_COMPLEX_FLOAT)
        !          5136:          return expand_complex_abs (opmode, op0, target, unsignedp);
        !          5137:       }
        !          5138: 
        !          5139:       /* Unsigned abs is simply the operand.  Testing here means we don't
        !          5140:         risk generating incorrect code below.  */
        !          5141:       if (TREE_UNSIGNED (type))
        !          5142:        return op0;
        !          5143: 
        !          5144:       /* First try to do it with a special abs instruction.  */
        !          5145:       temp = expand_unop (mode, abs_optab, op0, target, 0);
        !          5146:       if (temp != 0)
        !          5147:        return temp;
        !          5148: 
        !          5149:       /* If this machine has expensive jumps, we can do integer absolute
        !          5150:         value of X as (((signed) x >> (W-1)) ^ x) - ((signed) x >> (W-1)),
        !          5151:         where W is the width of MODE.  */
        !          5152: 
        !          5153:       if (GET_MODE_CLASS (mode) == MODE_INT && BRANCH_COST >= 2)
        !          5154:        {
        !          5155:          rtx extended = expand_shift (RSHIFT_EXPR, mode, op0,
        !          5156:                                       size_int (GET_MODE_BITSIZE (mode) - 1),
        !          5157:                                       NULL_RTX, 0);
        !          5158: 
        !          5159:          temp = expand_binop (mode, xor_optab, extended, op0, target, 0,
        !          5160:                               OPTAB_LIB_WIDEN);
        !          5161:          if (temp != 0)
        !          5162:            temp = expand_binop (mode, sub_optab, temp, extended, target, 0,
        !          5163:                                 OPTAB_LIB_WIDEN);
        !          5164: 
        !          5165:          if (temp != 0)
        !          5166:            return temp;
        !          5167:        }
        !          5168: 
        !          5169:       /* If that does not win, use conditional jump and negate.  */
        !          5170:       target = original_target;
        !          5171:       temp = gen_label_rtx ();
        !          5172:       if (target == 0 || ! safe_from_p (target, TREE_OPERAND (exp, 0))
        !          5173:          || (GET_CODE (target) == MEM && MEM_VOLATILE_P (target))
        !          5174:          || (GET_CODE (target) == REG
        !          5175:              && REGNO (target) < FIRST_PSEUDO_REGISTER))
        !          5176:        target = gen_reg_rtx (mode);
        !          5177:       emit_move_insn (target, op0);
        !          5178:       emit_cmp_insn (target,
        !          5179:                     expand_expr (convert (type, integer_zero_node),
        !          5180:                                  NULL_RTX, VOIDmode, 0),
        !          5181:                     GE, NULL_RTX, mode, 0, 0);
        !          5182:       NO_DEFER_POP;
        !          5183:       emit_jump_insn (gen_bge (temp));
        !          5184:       op0 = expand_unop (mode, neg_optab, target, target, 0);
        !          5185:       if (op0 != target)
        !          5186:        emit_move_insn (target, op0);
        !          5187:       emit_label (temp);
        !          5188:       OK_DEFER_POP;
        !          5189:       return target;
        !          5190: 
        !          5191:     case MAX_EXPR:
        !          5192:     case MIN_EXPR:
        !          5193:       target = original_target;
        !          5194:       if (target == 0 || ! safe_from_p (target, TREE_OPERAND (exp, 1))
        !          5195:          || (GET_CODE (target) == MEM && MEM_VOLATILE_P (target))
        !          5196:          || (GET_CODE (target) == REG
        !          5197:              && REGNO (target) < FIRST_PSEUDO_REGISTER))
        !          5198:        target = gen_reg_rtx (mode);
        !          5199:       op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
        !          5200:       op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0);
        !          5201: 
        !          5202:       /* First try to do it with a special MIN or MAX instruction.
        !          5203:         If that does not win, use a conditional jump to select the proper
        !          5204:         value.  */
        !          5205:       this_optab = (TREE_UNSIGNED (type)
        !          5206:                    ? (code == MIN_EXPR ? umin_optab : umax_optab)
        !          5207:                    : (code == MIN_EXPR ? smin_optab : smax_optab));
        !          5208: 
        !          5209:       temp = expand_binop (mode, this_optab, op0, op1, target, unsignedp,
        !          5210:                           OPTAB_WIDEN);
        !          5211:       if (temp != 0)
        !          5212:        return temp;
        !          5213: 
        !          5214:       if (target != op0)
        !          5215:        emit_move_insn (target, op0);
        !          5216:       op0 = gen_label_rtx ();
        !          5217:       /* If this mode is an integer too wide to compare properly,
        !          5218:         compare word by word.  Rely on cse to optimize constant cases.  */
        !          5219:       if (GET_MODE_CLASS (mode) == MODE_INT
        !          5220:          && !can_compare_p (mode))
        !          5221:        {
        !          5222:          if (code == MAX_EXPR)
        !          5223:            do_jump_by_parts_greater_rtx (mode, TREE_UNSIGNED (type), target, op1, NULL, op0);
        !          5224:          else
        !          5225:            do_jump_by_parts_greater_rtx (mode, TREE_UNSIGNED (type), op1, target, NULL, op0);
        !          5226:          emit_move_insn (target, op1);
        !          5227:        }
        !          5228:       else
        !          5229:        {
        !          5230:          if (code == MAX_EXPR)
        !          5231:            temp = (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 1)))
        !          5232:                    ? compare_from_rtx (target, op1, GEU, 1, mode, NULL_RTX, 0)
        !          5233:                    : compare_from_rtx (target, op1, GE, 0, mode, NULL_RTX, 0));
        !          5234:          else
        !          5235:            temp = (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 1)))
        !          5236:                    ? compare_from_rtx (target, op1, LEU, 1, mode, NULL_RTX, 0)
        !          5237:                    : compare_from_rtx (target, op1, LE, 0, mode, NULL_RTX, 0));
        !          5238:          if (temp == const0_rtx)
        !          5239:            emit_move_insn (target, op1);
        !          5240:          else if (temp != const_true_rtx)
        !          5241:            {
        !          5242:              if (bcc_gen_fctn[(int) GET_CODE (temp)] != 0)
        !          5243:                emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (temp)]) (op0));
        !          5244:              else
        !          5245:                abort ();
        !          5246:              emit_move_insn (target, op1);
        !          5247:            }
        !          5248:        }
        !          5249:       emit_label (op0);
        !          5250:       return target;
        !          5251: 
        !          5252: /* ??? Can optimize when the operand of this is a bitwise operation,
        !          5253:    by using a different bitwise operation.  */
        !          5254:     case BIT_NOT_EXPR:
        !          5255:       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
        !          5256:       temp = expand_unop (mode, one_cmpl_optab, op0, target, 1);
        !          5257:       if (temp == 0)
        !          5258:        abort ();
        !          5259:       return temp;
        !          5260: 
        !          5261:     case FFS_EXPR:
        !          5262:       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
        !          5263:       temp = expand_unop (mode, ffs_optab, op0, target, 1);
        !          5264:       if (temp == 0)
        !          5265:        abort ();
        !          5266:       return temp;
        !          5267: 
        !          5268: /* ??? Can optimize bitwise operations with one arg constant.
        !          5269:    Can optimize (a bitwise1 n) bitwise2 (a bitwise3 b)
        !          5270:    and (a bitwise1 b) bitwise2 b (etc)
        !          5271:    but that is probably not worth while.  */
        !          5272: 
        !          5273: /* BIT_AND_EXPR is for bitwise anding.
        !          5274:    TRUTH_AND_EXPR is for anding two boolean values
        !          5275:    when we want in all cases to compute both of them.
        !          5276:    In general it is fastest to do TRUTH_AND_EXPR by
        !          5277:    computing both operands as actual zero-or-1 values
        !          5278:    and then bitwise anding.  In cases where there cannot
        !          5279:    be any side effects, better code would be made by
        !          5280:    treating TRUTH_AND_EXPR like TRUTH_ANDIF_EXPR;
        !          5281:    but the question is how to recognize those cases.  */
        !          5282: 
        !          5283:       /* TRUTH_AND_EXPR can have a result whose mode doesn't match
        !          5284:         th operands.  If so, don't use our target.  */
        !          5285:     case TRUTH_AND_EXPR:
        !          5286:       if (mode != TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
        !          5287:        subtarget = 0;
        !          5288:     case BIT_AND_EXPR:
        !          5289:       this_optab = and_optab;
        !          5290:       goto binop;
        !          5291: 
        !          5292: /* See comment above about TRUTH_AND_EXPR; it applies here too.  */
        !          5293:     case TRUTH_OR_EXPR:
        !          5294:       if (mode != TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
        !          5295:        subtarget = 0;
        !          5296:     case BIT_IOR_EXPR:
        !          5297:       this_optab = ior_optab;
        !          5298:       goto binop;
        !          5299: 
        !          5300:     case TRUTH_XOR_EXPR:
        !          5301:       if (mode != TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
        !          5302:        subtarget = 0;
        !          5303:     case BIT_XOR_EXPR:
        !          5304:       this_optab = xor_optab;
        !          5305:       goto binop;
        !          5306: 
        !          5307:     case LSHIFT_EXPR:
        !          5308:     case RSHIFT_EXPR:
        !          5309:     case LROTATE_EXPR:
        !          5310:     case RROTATE_EXPR:
        !          5311:       preexpand_calls (exp);
        !          5312:       if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1)))
        !          5313:        subtarget = 0;
        !          5314:       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
        !          5315:       return expand_shift (code, mode, op0, TREE_OPERAND (exp, 1), target,
        !          5316:                           unsignedp);
        !          5317: 
        !          5318: /* Could determine the answer when only additive constants differ.
        !          5319:    Also, the addition of one can be handled by changing the condition.  */
        !          5320:     case LT_EXPR:
        !          5321:     case LE_EXPR:
        !          5322:     case GT_EXPR:
        !          5323:     case GE_EXPR:
        !          5324:     case EQ_EXPR:
        !          5325:     case NE_EXPR:
        !          5326:       preexpand_calls (exp);
        !          5327:       temp = do_store_flag (exp, target, tmode != VOIDmode ? tmode : mode, 0);
        !          5328:       if (temp != 0)
        !          5329:        return temp;
        !          5330:       /* For foo != 0, load foo, and if it is nonzero load 1 instead. */
        !          5331:       if (code == NE_EXPR && integer_zerop (TREE_OPERAND (exp, 1))
        !          5332:          && original_target
        !          5333:          && GET_CODE (original_target) == REG
        !          5334:          && (GET_MODE (original_target)
        !          5335:              == TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
        !          5336:        {
        !          5337:          temp = expand_expr (TREE_OPERAND (exp, 0), original_target, VOIDmode, 0);
        !          5338:          if (temp != original_target)
        !          5339:            temp = copy_to_reg (temp);
        !          5340:          op1 = gen_label_rtx ();
        !          5341:          emit_cmp_insn (temp, const0_rtx, EQ, NULL_RTX,
        !          5342:                         GET_MODE (temp), unsignedp, 0);
        !          5343:          emit_jump_insn (gen_beq (op1));
        !          5344:          emit_move_insn (temp, const1_rtx);
        !          5345:          emit_label (op1);
        !          5346:          return temp;
        !          5347:        }
        !          5348:       /* If no set-flag instruction, must generate a conditional
        !          5349:         store into a temporary variable.  Drop through
        !          5350:         and handle this like && and ||.  */
        !          5351: 
        !          5352:     case TRUTH_ANDIF_EXPR:
        !          5353:     case TRUTH_ORIF_EXPR:
        !          5354:       if (! ignore
        !          5355:          && (target == 0 || ! safe_from_p (target, exp)
        !          5356:              /* Make sure we don't have a hard reg (such as function's return
        !          5357:                 value) live across basic blocks, if not optimizing.  */
        !          5358:              || (!optimize && GET_CODE (target) == REG
        !          5359:                  && REGNO (target) < FIRST_PSEUDO_REGISTER)))
        !          5360:        target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
        !          5361: 
        !          5362:       if (target)
        !          5363:        emit_clr_insn (target);
        !          5364: 
        !          5365:       op1 = gen_label_rtx ();
        !          5366:       jumpifnot (exp, op1);
        !          5367: 
        !          5368:       if (target)
        !          5369:        emit_0_to_1_insn (target);
        !          5370: 
        !          5371:       emit_label (op1);
        !          5372:       return ignore ? const0_rtx : target;
        !          5373: 
        !          5374:     case TRUTH_NOT_EXPR:
        !          5375:       op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0);
        !          5376:       /* The parser is careful to generate TRUTH_NOT_EXPR
        !          5377:         only with operands that are always zero or one.  */
        !          5378:       temp = expand_binop (mode, xor_optab, op0, const1_rtx,
        !          5379:                           target, 1, OPTAB_LIB_WIDEN);
        !          5380:       if (temp == 0)
        !          5381:        abort ();
        !          5382:       return temp;
        !          5383: 
        !          5384:     case COMPOUND_EXPR:
        !          5385:       expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0);
        !          5386:       emit_queue ();
        !          5387:       return expand_expr (TREE_OPERAND (exp, 1),
        !          5388:                          (ignore ? const0_rtx : target),
        !          5389:                          VOIDmode, 0);
        !          5390: 
        !          5391:     case COND_EXPR:
        !          5392:       {
        !          5393:        /* Note that COND_EXPRs whose type is a structure or union
        !          5394:           are required to be constructed to contain assignments of
        !          5395:           a temporary variable, so that we can evaluate them here
        !          5396:           for side effect only.  If type is void, we must do likewise.  */
        !          5397: 
        !          5398:        /* If an arm of the branch requires a cleanup,
        !          5399:           only that cleanup is performed.  */
        !          5400: 
        !          5401:        tree singleton = 0;
        !          5402:        tree binary_op = 0, unary_op = 0;
        !          5403:        tree old_cleanups = cleanups_this_call;
        !          5404:        cleanups_this_call = 0;
        !          5405: 
        !          5406:        /* If this is (A ? 1 : 0) and A is a condition, just evaluate it and
        !          5407:           convert it to our mode, if necessary.  */
        !          5408:        if (integer_onep (TREE_OPERAND (exp, 1))
        !          5409:            && integer_zerop (TREE_OPERAND (exp, 2))
        !          5410:            && TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == '<')
        !          5411:          {
        !          5412:            if (ignore)
        !          5413:              {
        !          5414:                expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode,
        !          5415:                             modifier);
        !          5416:                return const0_rtx;
        !          5417:              }
        !          5418: 
        !          5419:            op0 = expand_expr (TREE_OPERAND (exp, 0), target, mode, modifier);
        !          5420:            if (GET_MODE (op0) == mode)
        !          5421:              return op0;
        !          5422:            if (target == 0)
        !          5423:              target = gen_reg_rtx (mode);
        !          5424:            convert_move (target, op0, unsignedp);
        !          5425:            return target;
        !          5426:          }
        !          5427: 
        !          5428:        /* If we are not to produce a result, we have no target.  Otherwise,
        !          5429:           if a target was specified use it; it will not be used as an
        !          5430:           intermediate target unless it is safe.  If no target, use a 
        !          5431:           temporary.  */
        !          5432: 
        !          5433:        if (ignore)
        !          5434:          temp = 0;
        !          5435:        else if (original_target
        !          5436:                 && safe_from_p (original_target, TREE_OPERAND (exp, 0)))
        !          5437:          temp = original_target;
        !          5438:        else if (mode == BLKmode)
        !          5439:          {
        !          5440:            if (TYPE_SIZE (type) == 0
        !          5441:                || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
        !          5442:              abort ();
        !          5443: 
        !          5444:            temp = assign_stack_temp (BLKmode,
        !          5445:                                      (TREE_INT_CST_LOW (TYPE_SIZE (type))
        !          5446:                                       + BITS_PER_UNIT - 1)
        !          5447:                                      / BITS_PER_UNIT, 0);
        !          5448:            MEM_IN_STRUCT_P (temp)
        !          5449:              = (TREE_CODE (type) == RECORD_TYPE
        !          5450:                 || TREE_CODE (type) == UNION_TYPE
        !          5451:                 || TREE_CODE (type) == QUAL_UNION_TYPE
        !          5452:                 || TREE_CODE (type) == ARRAY_TYPE);
        !          5453:          }
        !          5454:        else
        !          5455:          temp = gen_reg_rtx (mode);
        !          5456: 
        !          5457:        /* Check for X ? A + B : A.  If we have this, we can copy
        !          5458:           A to the output and conditionally add B.  Similarly for unary
        !          5459:           operations.  Don't do this if X has side-effects because
        !          5460:           those side effects might affect A or B and the "?" operation is
        !          5461:           a sequence point in ANSI.  (We test for side effects later.)  */
        !          5462: 
        !          5463:        if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 1))) == '2'
        !          5464:            && operand_equal_p (TREE_OPERAND (exp, 2),
        !          5465:                                TREE_OPERAND (TREE_OPERAND (exp, 1), 0), 0))
        !          5466:          singleton = TREE_OPERAND (exp, 2), binary_op = TREE_OPERAND (exp, 1);
        !          5467:        else if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 2))) == '2'
        !          5468:                 && operand_equal_p (TREE_OPERAND (exp, 1),
        !          5469:                                     TREE_OPERAND (TREE_OPERAND (exp, 2), 0), 0))
        !          5470:          singleton = TREE_OPERAND (exp, 1), binary_op = TREE_OPERAND (exp, 2);
        !          5471:        else if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 1))) == '1'
        !          5472:                 && operand_equal_p (TREE_OPERAND (exp, 2),
        !          5473:                                     TREE_OPERAND (TREE_OPERAND (exp, 1), 0), 0))
        !          5474:          singleton = TREE_OPERAND (exp, 2), unary_op = TREE_OPERAND (exp, 1);
        !          5475:        else if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 2))) == '1'
        !          5476:                 && operand_equal_p (TREE_OPERAND (exp, 1),
        !          5477:                                     TREE_OPERAND (TREE_OPERAND (exp, 2), 0), 0))
        !          5478:          singleton = TREE_OPERAND (exp, 1), unary_op = TREE_OPERAND (exp, 2);
        !          5479: 
        !          5480:        /* If we had X ? A + 1 : A and we can do the test of X as a store-flag
        !          5481:           operation, do this as A + (X != 0).  Similarly for other simple
        !          5482:           binary operators.  */
        !          5483:        if (temp && singleton && binary_op
        !          5484:            && ! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 0))
        !          5485:            && (TREE_CODE (binary_op) == PLUS_EXPR
        !          5486:                || TREE_CODE (binary_op) == MINUS_EXPR
        !          5487:                || TREE_CODE (binary_op) == BIT_IOR_EXPR
        !          5488:                || TREE_CODE (binary_op) == BIT_XOR_EXPR
        !          5489:                || TREE_CODE (binary_op) == BIT_AND_EXPR)
        !          5490:            && integer_onep (TREE_OPERAND (binary_op, 1))
        !          5491:            && TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == '<')
        !          5492:          {
        !          5493:            rtx result;
        !          5494:            optab boptab = (TREE_CODE (binary_op) == PLUS_EXPR ? add_optab
        !          5495:                            : TREE_CODE (binary_op) == MINUS_EXPR ? sub_optab
        !          5496:                            : TREE_CODE (binary_op) == BIT_IOR_EXPR ? ior_optab
        !          5497:                            : TREE_CODE (binary_op) == BIT_XOR_EXPR ? xor_optab
        !          5498:                            : and_optab);
        !          5499: 
        !          5500:            /* If we had X ? A : A + 1, do this as A + (X == 0).
        !          5501: 
        !          5502:               We have to invert the truth value here and then put it
        !          5503:               back later if do_store_flag fails.  We cannot simply copy
        !          5504:               TREE_OPERAND (exp, 0) to another variable and modify that
        !          5505:               because invert_truthvalue can modify the tree pointed to
        !          5506:               by its argument.  */
        !          5507:            if (singleton == TREE_OPERAND (exp, 1))
        !          5508:              TREE_OPERAND (exp, 0)
        !          5509:                = invert_truthvalue (TREE_OPERAND (exp, 0));
        !          5510: 
        !          5511:            result = do_store_flag (TREE_OPERAND (exp, 0),
        !          5512:                                    (safe_from_p (temp, singleton)
        !          5513:                                     ? temp : NULL_RTX),
        !          5514:                                    mode, BRANCH_COST <= 1);
        !          5515: 
        !          5516:            if (result)
        !          5517:              {
        !          5518:                op1 = expand_expr (singleton, NULL_RTX, VOIDmode, 0);
        !          5519:                return expand_binop (mode, boptab, op1, result, temp,
        !          5520:                                     unsignedp, OPTAB_LIB_WIDEN);
        !          5521:              }
        !          5522:            else if (singleton == TREE_OPERAND (exp, 1))
        !          5523:              TREE_OPERAND (exp, 0)
        !          5524:                = invert_truthvalue (TREE_OPERAND (exp, 0));
        !          5525:          }
        !          5526:            
        !          5527:        NO_DEFER_POP;
        !          5528:        op0 = gen_label_rtx ();
        !          5529: 
        !          5530:        if (singleton && ! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 0)))
        !          5531:          {
        !          5532:            if (temp != 0)
        !          5533:              {
        !          5534:                /* If the target conflicts with the other operand of the
        !          5535:                   binary op, we can't use it.  Also, we can't use the target
        !          5536:                   if it is a hard register, because evaluating the condition
        !          5537:                   might clobber it.  */
        !          5538:                if ((binary_op
        !          5539:                     && ! safe_from_p (temp, TREE_OPERAND (binary_op, 1)))
        !          5540:                    || (GET_CODE (temp) == REG
        !          5541:                        && REGNO (temp) < FIRST_PSEUDO_REGISTER))
        !          5542:                  temp = gen_reg_rtx (mode);
        !          5543:                store_expr (singleton, temp, 0);
        !          5544:              }
        !          5545:            else
        !          5546:              expand_expr (singleton,
        !          5547:                           ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
        !          5548:            if (cleanups_this_call)
        !          5549:              {
        !          5550:                sorry ("aggregate value in COND_EXPR");
        !          5551:                cleanups_this_call = 0;
        !          5552:              }
        !          5553:            if (singleton == TREE_OPERAND (exp, 1))
        !          5554:              jumpif (TREE_OPERAND (exp, 0), op0);
        !          5555:            else
        !          5556:              jumpifnot (TREE_OPERAND (exp, 0), op0);
        !          5557: 
        !          5558:            if (binary_op && temp == 0)
        !          5559:              /* Just touch the other operand.  */
        !          5560:              expand_expr (TREE_OPERAND (binary_op, 1),
        !          5561:                           ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
        !          5562:            else if (binary_op)
        !          5563:              store_expr (build (TREE_CODE (binary_op), type,
        !          5564:                                 make_tree (type, temp),
        !          5565:                                 TREE_OPERAND (binary_op, 1)),
        !          5566:                          temp, 0);
        !          5567:            else
        !          5568:              store_expr (build1 (TREE_CODE (unary_op), type,
        !          5569:                                  make_tree (type, temp)),
        !          5570:                          temp, 0);
        !          5571:            op1 = op0;
        !          5572:          }
        !          5573: #if 0
        !          5574:        /* This is now done in jump.c and is better done there because it
        !          5575:           produces shorter register lifetimes.  */
        !          5576:           
        !          5577:        /* Check for both possibilities either constants or variables
        !          5578:           in registers (but not the same as the target!).  If so, can
        !          5579:           save branches by assigning one, branching, and assigning the
        !          5580:           other.  */
        !          5581:        else if (temp && GET_MODE (temp) != BLKmode
        !          5582:                 && (TREE_CONSTANT (TREE_OPERAND (exp, 1))
        !          5583:                     || ((TREE_CODE (TREE_OPERAND (exp, 1)) == PARM_DECL
        !          5584:                          || TREE_CODE (TREE_OPERAND (exp, 1)) == VAR_DECL)
        !          5585:                         && DECL_RTL (TREE_OPERAND (exp, 1))
        !          5586:                         && GET_CODE (DECL_RTL (TREE_OPERAND (exp, 1))) == REG
        !          5587:                         && DECL_RTL (TREE_OPERAND (exp, 1)) != temp))
        !          5588:                 && (TREE_CONSTANT (TREE_OPERAND (exp, 2))
        !          5589:                     || ((TREE_CODE (TREE_OPERAND (exp, 2)) == PARM_DECL
        !          5590:                          || TREE_CODE (TREE_OPERAND (exp, 2)) == VAR_DECL)
        !          5591:                         && DECL_RTL (TREE_OPERAND (exp, 2))
        !          5592:                         && GET_CODE (DECL_RTL (TREE_OPERAND (exp, 2))) == REG
        !          5593:                         && DECL_RTL (TREE_OPERAND (exp, 2)) != temp)))
        !          5594:          {
        !          5595:            if (GET_CODE (temp) == REG && REGNO (temp) < FIRST_PSEUDO_REGISTER)
        !          5596:              temp = gen_reg_rtx (mode);
        !          5597:            store_expr (TREE_OPERAND (exp, 2), temp, 0);
        !          5598:            jumpifnot (TREE_OPERAND (exp, 0), op0);
        !          5599:            store_expr (TREE_OPERAND (exp, 1), temp, 0);
        !          5600:            op1 = op0;
        !          5601:          }
        !          5602: #endif
        !          5603:        /* Check for A op 0 ? A : FOO and A op 0 ? FOO : A where OP is any
        !          5604:           comparison operator.  If we have one of these cases, set the
        !          5605:           output to A, branch on A (cse will merge these two references),
        !          5606:           then set the output to FOO.  */
        !          5607:        else if (temp
        !          5608:                 && TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == '<'
        !          5609:                 && integer_zerop (TREE_OPERAND (TREE_OPERAND (exp, 0), 1))
        !          5610:                 && operand_equal_p (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
        !          5611:                                     TREE_OPERAND (exp, 1), 0)
        !          5612:                 && ! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 0))
        !          5613:                 && safe_from_p (temp, TREE_OPERAND (exp, 2)))
        !          5614:          {
        !          5615:            if (GET_CODE (temp) == REG && REGNO (temp) < FIRST_PSEUDO_REGISTER)
        !          5616:              temp = gen_reg_rtx (mode);
        !          5617:            store_expr (TREE_OPERAND (exp, 1), temp, 0);
        !          5618:            jumpif (TREE_OPERAND (exp, 0), op0);
        !          5619:            store_expr (TREE_OPERAND (exp, 2), temp, 0);
        !          5620:            op1 = op0;
        !          5621:          }
        !          5622:        else if (temp
        !          5623:                 && TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == '<'
        !          5624:                 && integer_zerop (TREE_OPERAND (TREE_OPERAND (exp, 0), 1))
        !          5625:                 && operand_equal_p (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
        !          5626:                                     TREE_OPERAND (exp, 2), 0)
        !          5627:                 && ! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 0))
        !          5628:                 && safe_from_p (temp, TREE_OPERAND (exp, 1)))
        !          5629:          {
        !          5630:            if (GET_CODE (temp) == REG && REGNO (temp) < FIRST_PSEUDO_REGISTER)
        !          5631:              temp = gen_reg_rtx (mode);
        !          5632:            store_expr (TREE_OPERAND (exp, 2), temp, 0);
        !          5633:            jumpifnot (TREE_OPERAND (exp, 0), op0);
        !          5634:            store_expr (TREE_OPERAND (exp, 1), temp, 0);
        !          5635:            op1 = op0;
        !          5636:          }
        !          5637:        else
        !          5638:          {
        !          5639:            op1 = gen_label_rtx ();
        !          5640:            jumpifnot (TREE_OPERAND (exp, 0), op0);
        !          5641:            if (temp != 0)
        !          5642:              store_expr (TREE_OPERAND (exp, 1), temp, 0);
        !          5643:            else
        !          5644:              expand_expr (TREE_OPERAND (exp, 1),
        !          5645:                           ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
        !          5646:            if (cleanups_this_call)
        !          5647:              {
        !          5648:                sorry ("aggregate value in COND_EXPR");
        !          5649:                cleanups_this_call = 0;
        !          5650:              }
        !          5651: 
        !          5652:            emit_queue ();
        !          5653:            emit_jump_insn (gen_jump (op1));
        !          5654:            emit_barrier ();
        !          5655:            emit_label (op0);
        !          5656:            if (temp != 0)
        !          5657:              store_expr (TREE_OPERAND (exp, 2), temp, 0);
        !          5658:            else
        !          5659:              expand_expr (TREE_OPERAND (exp, 2),
        !          5660:                           ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
        !          5661:          }
        !          5662: 
        !          5663:        if (cleanups_this_call)
        !          5664:          {
        !          5665:            sorry ("aggregate value in COND_EXPR");
        !          5666:            cleanups_this_call = 0;
        !          5667:          }
        !          5668: 
        !          5669:        emit_queue ();
        !          5670:        emit_label (op1);
        !          5671:        OK_DEFER_POP;
        !          5672:        cleanups_this_call = old_cleanups;
        !          5673:        return temp;
        !          5674:       }
        !          5675: 
        !          5676:     case TARGET_EXPR:
        !          5677:       {
        !          5678:        /* Something needs to be initialized, but we didn't know
        !          5679:           where that thing was when building the tree.  For example,
        !          5680:           it could be the return value of a function, or a parameter
        !          5681:           to a function which lays down in the stack, or a temporary
        !          5682:           variable which must be passed by reference.
        !          5683: 
        !          5684:           We guarantee that the expression will either be constructed
        !          5685:           or copied into our original target.  */
        !          5686: 
        !          5687:        tree slot = TREE_OPERAND (exp, 0);
        !          5688:        tree exp1;
        !          5689: 
        !          5690:        if (TREE_CODE (slot) != VAR_DECL)
        !          5691:          abort ();
        !          5692: 
        !          5693:        if (target == 0)
        !          5694:          {
        !          5695:            if (DECL_RTL (slot) != 0)
        !          5696:              {
        !          5697:                target = DECL_RTL (slot);
        !          5698:                /* If we have already expanded the slot, so don't do
        !          5699:                   it again.  (mrs)  */
        !          5700:                if (TREE_OPERAND (exp, 1) == NULL_TREE)
        !          5701:                  return target;
        !          5702:              }
        !          5703:            else
        !          5704:              {
        !          5705:                target = assign_stack_temp (mode, int_size_in_bytes (type), 0);
        !          5706:                /* All temp slots at this level must not conflict.  */
        !          5707:                preserve_temp_slots (target);
        !          5708:                DECL_RTL (slot) = target;
        !          5709:              }
        !          5710: 
        !          5711:            /* We set IGNORE when we know that we're already
        !          5712:               doing this for a cleanup.  */
        !          5713:            if (ignore == 0)
        !          5714:              {
        !          5715:                /* Since SLOT is not known to the called function
        !          5716:                   to belong to its stack frame, we must build an explicit
        !          5717:                   cleanup.  This case occurs when we must build up a reference
        !          5718:                   to pass the reference as an argument.  In this case,
        !          5719:                   it is very likely that such a reference need not be
        !          5720:                   built here.  */
        !          5721: 
        !          5722:                if (TREE_OPERAND (exp, 2) == 0)
        !          5723:                  TREE_OPERAND (exp, 2) = maybe_build_cleanup (slot);
        !          5724:                if (TREE_OPERAND (exp, 2))
        !          5725:                  cleanups_this_call = tree_cons (NULL_TREE, TREE_OPERAND (exp, 2),
        !          5726:                                                  cleanups_this_call);
        !          5727:              }
        !          5728:          }
        !          5729:        else
        !          5730:          {
        !          5731:            /* This case does occur, when expanding a parameter which
        !          5732:               needs to be constructed on the stack.  The target
        !          5733:               is the actual stack address that we want to initialize.
        !          5734:               The function we call will perform the cleanup in this case.  */
        !          5735: 
        !          5736:            /* If we have already assigned it space, use that space,
        !          5737:               not target that we were passed in, as our target
        !          5738:               parameter is only a hint.  */
        !          5739:            if (DECL_RTL (slot) != 0)
        !          5740:               {
        !          5741:                 target = DECL_RTL (slot);
        !          5742:                 /* If we have already expanded the slot, so don't do
        !          5743:                    it again.  (mrs)  */
        !          5744:                 if (TREE_OPERAND (exp, 1) == NULL_TREE)
        !          5745:                   return target;
        !          5746:              }
        !          5747: 
        !          5748:            DECL_RTL (slot) = target;
        !          5749:          }
        !          5750: 
        !          5751:        exp1 = TREE_OPERAND (exp, 1);
        !          5752:        /* Mark it as expanded.  */
        !          5753:        TREE_OPERAND (exp, 1) = NULL_TREE;
        !          5754: 
        !          5755:        return expand_expr (exp1, target, tmode, modifier);
        !          5756:       }
        !          5757: 
        !          5758:     case INIT_EXPR:
        !          5759:       {
        !          5760:        tree lhs = TREE_OPERAND (exp, 0);
        !          5761:        tree rhs = TREE_OPERAND (exp, 1);
        !          5762:        tree noncopied_parts = 0;
        !          5763:        tree lhs_type = TREE_TYPE (lhs);
        !          5764: 
        !          5765:        temp = expand_assignment (lhs, rhs, ! ignore, original_target != 0);
        !          5766:        if (TYPE_NONCOPIED_PARTS (lhs_type) != 0 && !fixed_type_p (rhs))
        !          5767:          noncopied_parts = init_noncopied_parts (stabilize_reference (lhs),
        !          5768:                                                  TYPE_NONCOPIED_PARTS (lhs_type));
        !          5769:        while (noncopied_parts != 0)
        !          5770:          {
        !          5771:            expand_assignment (TREE_VALUE (noncopied_parts),
        !          5772:                               TREE_PURPOSE (noncopied_parts), 0, 0);
        !          5773:            noncopied_parts = TREE_CHAIN (noncopied_parts);
        !          5774:          }
        !          5775:        return temp;
        !          5776:       }
        !          5777: 
        !          5778:     case MODIFY_EXPR:
        !          5779:       {
        !          5780:        /* If lhs is complex, expand calls in rhs before computing it.
        !          5781:           That's so we don't compute a pointer and save it over a call.
        !          5782:           If lhs is simple, compute it first so we can give it as a
        !          5783:           target if the rhs is just a call.  This avoids an extra temp and copy
        !          5784:           and that prevents a partial-subsumption which makes bad code.
        !          5785:           Actually we could treat component_ref's of vars like vars.  */
        !          5786: 
        !          5787:        tree lhs = TREE_OPERAND (exp, 0);
        !          5788:        tree rhs = TREE_OPERAND (exp, 1);
        !          5789:        tree noncopied_parts = 0;
        !          5790:        tree lhs_type = TREE_TYPE (lhs);
        !          5791: 
        !          5792:        temp = 0;
        !          5793: 
        !          5794:        if (TREE_CODE (lhs) != VAR_DECL
        !          5795:            && TREE_CODE (lhs) != RESULT_DECL
        !          5796:            && TREE_CODE (lhs) != PARM_DECL)
        !          5797:          preexpand_calls (exp);
        !          5798: 
        !          5799:        /* Check for |= or &= of a bitfield of size one into another bitfield
        !          5800:           of size 1.  In this case, (unless we need the result of the
        !          5801:           assignment) we can do this more efficiently with a
        !          5802:           test followed by an assignment, if necessary.
        !          5803: 
        !          5804:           ??? At this point, we can't get a BIT_FIELD_REF here.  But if
        !          5805:           things change so we do, this code should be enhanced to
        !          5806:           support it.  */
        !          5807:        if (ignore
        !          5808:            && TREE_CODE (lhs) == COMPONENT_REF
        !          5809:            && (TREE_CODE (rhs) == BIT_IOR_EXPR
        !          5810:                || TREE_CODE (rhs) == BIT_AND_EXPR)
        !          5811:            && TREE_OPERAND (rhs, 0) == lhs
        !          5812:            && TREE_CODE (TREE_OPERAND (rhs, 1)) == COMPONENT_REF
        !          5813:            && TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (lhs, 1))) == 1
        !          5814:            && TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (TREE_OPERAND (rhs, 1), 1))) == 1)
        !          5815:          {
        !          5816:            rtx label = gen_label_rtx ();
        !          5817: 
        !          5818:            do_jump (TREE_OPERAND (rhs, 1),
        !          5819:                     TREE_CODE (rhs) == BIT_IOR_EXPR ? label : 0,
        !          5820:                     TREE_CODE (rhs) == BIT_AND_EXPR ? label : 0);
        !          5821:            expand_assignment (lhs, convert (TREE_TYPE (rhs),
        !          5822:                                             (TREE_CODE (rhs) == BIT_IOR_EXPR
        !          5823:                                              ? integer_one_node
        !          5824:                                              : integer_zero_node)),
        !          5825:                               0, 0);
        !          5826:            do_pending_stack_adjust ();
        !          5827:            emit_label (label);
        !          5828:            return const0_rtx;
        !          5829:          }
        !          5830: 
        !          5831:        if (TYPE_NONCOPIED_PARTS (lhs_type) != 0
        !          5832:            && ! (fixed_type_p (lhs) && fixed_type_p (rhs)))
        !          5833:          noncopied_parts = save_noncopied_parts (stabilize_reference (lhs),
        !          5834:                                                  TYPE_NONCOPIED_PARTS (lhs_type));
        !          5835: 
        !          5836:        temp = expand_assignment (lhs, rhs, ! ignore, original_target != 0);
        !          5837:        while (noncopied_parts != 0)
        !          5838:          {
        !          5839:            expand_assignment (TREE_PURPOSE (noncopied_parts),
        !          5840:                               TREE_VALUE (noncopied_parts), 0, 0);
        !          5841:            noncopied_parts = TREE_CHAIN (noncopied_parts);
        !          5842:          }
        !          5843:        return temp;
        !          5844:       }
        !          5845: 
        !          5846:     case PREINCREMENT_EXPR:
        !          5847:     case PREDECREMENT_EXPR:
        !          5848:       return expand_increment (exp, 0);
        !          5849: 
        !          5850:     case POSTINCREMENT_EXPR:
        !          5851:     case POSTDECREMENT_EXPR:
        !          5852:       /* Faster to treat as pre-increment if result is not used.  */
        !          5853:       return expand_increment (exp, ! ignore);
        !          5854: 
        !          5855:     case ADDR_EXPR:
        !          5856:       /* Are we taking the address of a nested function?  */
        !          5857:       if (TREE_CODE (TREE_OPERAND (exp, 0)) == FUNCTION_DECL
        !          5858:          && decl_function_context (TREE_OPERAND (exp, 0)) != 0)
        !          5859:        {
        !          5860:          op0 = trampoline_address (TREE_OPERAND (exp, 0));
        !          5861:          op0 = force_operand (op0, target);
        !          5862:        }
        !          5863:       else
        !          5864:        {
        !          5865:          /* We make sure to pass const0_rtx down if we came in with
        !          5866:             ignore set, to avoid doing the cleanups twice for something.  */
        !          5867:          op0 = expand_expr (TREE_OPERAND (exp, 0),
        !          5868:                             ignore ? const0_rtx : NULL_RTX, VOIDmode,
        !          5869:                             (modifier == EXPAND_INITIALIZER
        !          5870:                              ? modifier : EXPAND_CONST_ADDRESS));
        !          5871: 
        !          5872:          /* We would like the object in memory.  If it is a constant,
        !          5873:             we can have it be statically allocated into memory.  For
        !          5874:             a non-constant (REG or SUBREG), we need to allocate some
        !          5875:             memory and store the value into it.  */
        !          5876: 
        !          5877:          if (CONSTANT_P (op0))
        !          5878:            op0 = force_const_mem (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))),
        !          5879:                                   op0);
        !          5880: 
        !          5881:          /* These cases happen in Fortran.  Is that legitimate?
        !          5882:             Should Fortran work in another way?
        !          5883:             Do they happen in C?  */
        !          5884:          if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
        !          5885:              || GET_CODE (op0) == CONCAT)
        !          5886:            {
        !          5887:              /* If this object is in a register, it must be not
        !          5888:                 be BLKmode. */
        !          5889:              tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
        !          5890:              enum machine_mode inner_mode = TYPE_MODE (inner_type);
        !          5891:              rtx memloc
        !          5892:                = assign_stack_temp (inner_mode,
        !          5893:                                     int_size_in_bytes (inner_type), 1);
        !          5894: 
        !          5895:              emit_move_insn (memloc, op0);
        !          5896:              op0 = memloc;
        !          5897:            }
        !          5898: 
        !          5899:          if (GET_CODE (op0) != MEM)
        !          5900:            abort ();
        !          5901:   
        !          5902:          if (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER)
        !          5903:            return XEXP (op0, 0);
        !          5904:          op0 = force_operand (XEXP (op0, 0), target);
        !          5905:        }
        !          5906:       if (flag_force_addr && GET_CODE (op0) != REG)
        !          5907:        return force_reg (Pmode, op0);
        !          5908:       return op0;
        !          5909: 
        !          5910:     case ENTRY_VALUE_EXPR:
        !          5911:       abort ();
        !          5912: 
        !          5913:     /* COMPLEX type for Extended Pascal & Fortran  */
        !          5914:     case COMPLEX_EXPR:
        !          5915:       {
        !          5916:        enum machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
        !          5917: 
        !          5918:        rtx prev;
        !          5919: 
        !          5920:        /* Get the rtx code of the operands.  */
        !          5921:        op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
        !          5922:        op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
        !          5923: 
        !          5924:        if (! target)
        !          5925:          target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
        !          5926: 
        !          5927:        prev = get_last_insn ();
        !          5928: 
        !          5929:        /* Tell flow that the whole of the destination is being set.  */
        !          5930:        if (GET_CODE (target) == REG)
        !          5931:          emit_insn (gen_rtx (CLOBBER, VOIDmode, target));
        !          5932: 
        !          5933:        /* Move the real (op0) and imaginary (op1) parts to their location.  */
        !          5934:        emit_move_insn (gen_realpart (mode, target), op0);
        !          5935:        emit_move_insn (gen_imagpart (mode, target), op1);
        !          5936: 
        !          5937:        /* Complex construction should appear as a single unit.  */
        !          5938:        if (GET_CODE (target) != CONCAT)
        !          5939:          /* If TARGET is a CONCAT, we got insns like RD = RS, ID = IS,
        !          5940:             each with a separate pseudo as destination.
        !          5941:             It's not correct for flow to treat them as a unit.  */
        !          5942:          group_insns (prev);
        !          5943: 
        !          5944:        return target;
        !          5945:       }
        !          5946: 
        !          5947:     case REALPART_EXPR:
        !          5948:       op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
        !          5949:       return gen_realpart (mode, op0);
        !          5950:       
        !          5951:     case IMAGPART_EXPR:
        !          5952:       op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
        !          5953:       return gen_imagpart (mode, op0);
        !          5954: 
        !          5955:     case CONJ_EXPR:
        !          5956:       {
        !          5957:        enum machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
        !          5958:        rtx imag_t;
        !          5959:        rtx prev;
        !          5960:        
        !          5961:        op0  = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
        !          5962: 
        !          5963:        if (! target)
        !          5964:          target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
        !          5965:                                                                    
        !          5966:        prev = get_last_insn ();
        !          5967: 
        !          5968:        /* Tell flow that the whole of the destination is being set.  */
        !          5969:        if (GET_CODE (target) == REG)
        !          5970:          emit_insn (gen_rtx (CLOBBER, VOIDmode, target));
        !          5971: 
        !          5972:        /* Store the realpart and the negated imagpart to target.  */
        !          5973:        emit_move_insn (gen_realpart (mode, target), gen_realpart (mode, op0));
        !          5974: 
        !          5975:        imag_t = gen_imagpart (mode, target);
        !          5976:        temp   = expand_unop (mode, neg_optab,
        !          5977:                              gen_imagpart (mode, op0), imag_t, 0);
        !          5978:        if (temp != imag_t)
        !          5979:          emit_move_insn (imag_t, temp);
        !          5980: 
        !          5981:        /* Conjugate should appear as a single unit */
        !          5982:        if (GET_CODE (target) != CONCAT)
        !          5983:          /* If TARGET is a CONCAT, we got insns like RD = RS, ID = - IS,
        !          5984:             each with a separate pseudo as destination.
        !          5985:             It's not correct for flow to treat them as a unit.  */
        !          5986:          group_insns (prev);
        !          5987: 
        !          5988:        return target;
        !          5989:       }
        !          5990: 
        !          5991:     case ERROR_MARK:
        !          5992:       op0 = CONST0_RTX (tmode);
        !          5993:       if (op0 != 0)
        !          5994:        return op0;
        !          5995:       return const0_rtx;
        !          5996: 
        !          5997:     default:
        !          5998:       return (*lang_expand_expr) (exp, original_target, tmode, modifier);
        !          5999:     }
        !          6000: 
        !          6001:   /* Here to do an ordinary binary operator, generating an instruction
        !          6002:      from the optab already placed in `this_optab'.  */
        !          6003:  binop:
        !          6004:   preexpand_calls (exp);
        !          6005:   if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1)))
        !          6006:     subtarget = 0;
        !          6007:   op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
        !          6008:   op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
        !          6009:  binop2:
        !          6010:   temp = expand_binop (mode, this_optab, op0, op1, target,
        !          6011:                       unsignedp, OPTAB_LIB_WIDEN);
        !          6012:   if (temp == 0)
        !          6013:     abort ();
        !          6014:   return temp;
        !          6015: }
        !          6016: 
        !          6017: 
        !          6018: /* Emit bytecode to evaluate the given expression EXP to the stack. */
        !          6019: void
        !          6020: bc_expand_expr (exp)
        !          6021:     tree exp;
        !          6022: {
        !          6023:   enum tree_code code;
        !          6024:   tree type, arg0;
        !          6025:   rtx r;
        !          6026:   struct binary_operator *binoptab;
        !          6027:   struct unary_operator *unoptab;
        !          6028:   struct increment_operator *incroptab;
        !          6029:   struct bc_label *lab, *lab1;
        !          6030:   enum bytecode_opcode opcode;
        !          6031:   
        !          6032:   
        !          6033:   code = TREE_CODE (exp);
        !          6034:   
        !          6035:   switch (code)
        !          6036:     {
        !          6037:     case PARM_DECL:
        !          6038:       
        !          6039:       if (DECL_RTL (exp) == 0)
        !          6040:        {
        !          6041:          error_with_decl (exp, "prior parameter's size depends on `%s'");
        !          6042:          return;
        !          6043:        }
        !          6044:       
        !          6045:       bc_load_parmaddr (DECL_RTL (exp));
        !          6046:       bc_load_memory (TREE_TYPE (exp), exp);
        !          6047:       
        !          6048:       return;
        !          6049:       
        !          6050:     case VAR_DECL:
        !          6051:       
        !          6052:       if (DECL_RTL (exp) == 0)
        !          6053:        abort ();
        !          6054:       
        !          6055: #if 0
        !          6056:       if (BYTECODE_LABEL (DECL_RTL (exp)))
        !          6057:        bc_load_externaddr (DECL_RTL (exp));
        !          6058:       else
        !          6059:        bc_load_localaddr (DECL_RTL (exp));
        !          6060: #endif
        !          6061:       if (TREE_PUBLIC (exp))
        !          6062:        bc_load_externaddr_id (DECL_ASSEMBLER_NAME (exp),
        !          6063:                               BYTECODE_BC_LABEL (DECL_RTL (exp))->offset);
        !          6064:       else
        !          6065:        bc_load_localaddr (DECL_RTL (exp));
        !          6066:       
        !          6067:       bc_load_memory (TREE_TYPE (exp), exp);
        !          6068:       return;
        !          6069:       
        !          6070:     case INTEGER_CST:
        !          6071:       
        !          6072: #ifdef DEBUG_PRINT_CODE
        !          6073:       fprintf (stderr, " [%x]\n", TREE_INT_CST_LOW (exp));
        !          6074: #endif
        !          6075:       bc_emit_instruction (mode_to_const_map[(int) (DECL_BIT_FIELD (exp)
        !          6076:                                             ? SImode
        !          6077:                                             : TYPE_MODE (TREE_TYPE (exp)))],
        !          6078:                           (HOST_WIDE_INT) TREE_INT_CST_LOW (exp));
        !          6079:       return;
        !          6080:       
        !          6081:     case REAL_CST:
        !          6082:       
        !          6083: #if 0
        !          6084: #ifdef DEBUG_PRINT_CODE
        !          6085:       fprintf (stderr, " [%g]\n", (double) TREE_INT_CST_LOW (exp));
        !          6086: #endif
        !          6087:       /* FIX THIS: find a better way to pass real_cst's. -bson */
        !          6088:       bc_emit_instruction (mode_to_const_map[TYPE_MODE (TREE_TYPE (exp))],
        !          6089:                           (double) TREE_REAL_CST (exp));
        !          6090: #else
        !          6091:       abort ();
        !          6092: #endif
        !          6093: 
        !          6094:       return;
        !          6095:       
        !          6096:     case CALL_EXPR:
        !          6097:       
        !          6098:       /* We build a call description vector describing the type of
        !          6099:         the return value and of the arguments; this call vector,
        !          6100:         together with a pointer to a location for the return value
        !          6101:         and the base of the argument list, is passed to the low
        !          6102:         level machine dependent call subroutine, which is responsible
        !          6103:         for putting the arguments wherever real functions expect
        !          6104:         them, as well as getting the return value back.  */
        !          6105:       {
        !          6106:        tree calldesc = 0, arg;
        !          6107:        int nargs = 0, i;
        !          6108:        rtx retval;
        !          6109:        
        !          6110:        /* Push the evaluated args on the evaluation stack in reverse
        !          6111:           order.  Also make an entry for each arg in the calldesc
        !          6112:           vector while we're at it.  */
        !          6113:        
        !          6114:        TREE_OPERAND (exp, 1) = nreverse (TREE_OPERAND (exp, 1));
        !          6115:        
        !          6116:        for (arg = TREE_OPERAND (exp, 1); arg; arg = TREE_CHAIN (arg))
        !          6117:          {
        !          6118:            ++nargs;
        !          6119:            bc_expand_expr (TREE_VALUE (arg));
        !          6120:            
        !          6121:            calldesc = tree_cons ((tree) 0,
        !          6122:                                  size_in_bytes (TREE_TYPE (TREE_VALUE (arg))),
        !          6123:                                  calldesc);
        !          6124:            calldesc = tree_cons ((tree) 0,
        !          6125:                                  bc_runtime_type_code (TREE_TYPE (TREE_VALUE (arg))),
        !          6126:                                  calldesc);
        !          6127:          }
        !          6128:        
        !          6129:        TREE_OPERAND (exp, 1) = nreverse (TREE_OPERAND (exp, 1));
        !          6130:        
        !          6131:        /* Allocate a location for the return value and push its
        !          6132:           address on the evaluation stack.  Also make an entry
        !          6133:           at the front of the calldesc for the return value type. */
        !          6134:        
        !          6135:        type = TREE_TYPE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0))));
        !          6136:        retval = bc_allocate_local (int_size_in_bytes (type), TYPE_ALIGN (type));
        !          6137:        bc_load_localaddr (retval);
        !          6138:        
        !          6139:        calldesc = tree_cons ((tree) 0, size_in_bytes (type), calldesc);
        !          6140:        calldesc = tree_cons ((tree) 0, bc_runtime_type_code (type), calldesc);
        !          6141:        
        !          6142:        /* Prepend the argument count.  */
        !          6143:        calldesc = tree_cons ((tree) 0,
        !          6144:                              build_int_2 (nargs, 0),
        !          6145:                              calldesc);
        !          6146:        
        !          6147:        /* Push the address of the call description vector on the stack.  */
        !          6148:        calldesc = build_nt (CONSTRUCTOR, (tree) 0, calldesc);
        !          6149:        TREE_TYPE (calldesc) = build_array_type (integer_type_node,
        !          6150:                                                 build_index_type (build_int_2 (nargs * 2, 0)));
        !          6151:        r = output_constant_def (calldesc);
        !          6152:        bc_load_externaddr (r);
        !          6153:        
        !          6154:        /* Push the address of the function to be called. */
        !          6155:        bc_expand_expr (TREE_OPERAND (exp, 0));
        !          6156:        
        !          6157:        /* Call the function, popping its address and the calldesc vector
        !          6158:           address off the evaluation stack in the process.  */
        !          6159:        bc_emit_instruction (call);
        !          6160:        
        !          6161:        /* Pop the arguments off the stack.  */
        !          6162:        bc_adjust_stack (nargs);
        !          6163:        
        !          6164:        /* Load the return value onto the stack.  */
        !          6165:        bc_load_localaddr (retval);
        !          6166:        bc_load_memory (type, TREE_OPERAND (exp, 0));
        !          6167:       }
        !          6168:       return;
        !          6169:       
        !          6170:     case SAVE_EXPR:
        !          6171:       
        !          6172:       if (!SAVE_EXPR_RTL (exp))
        !          6173:        {
        !          6174:          /* First time around: copy to local variable */
        !          6175:          SAVE_EXPR_RTL (exp) = bc_allocate_local (int_size_in_bytes (TREE_TYPE (exp)),
        !          6176:                                                   TYPE_ALIGN (TREE_TYPE(exp)));
        !          6177:          bc_expand_expr (TREE_OPERAND (exp, 0));
        !          6178:          bc_emit_instruction (duplicate);
        !          6179:          
        !          6180:          bc_load_localaddr (SAVE_EXPR_RTL (exp));
        !          6181:          bc_store_memory (TREE_TYPE (exp), TREE_OPERAND (exp, 0));
        !          6182:        }
        !          6183:       else
        !          6184:        {
        !          6185:          /* Consecutive reference: use saved copy */
        !          6186:          bc_load_localaddr (SAVE_EXPR_RTL (exp));
        !          6187:          bc_load_memory (TREE_TYPE (exp), TREE_OPERAND (exp, 0));
        !          6188:        }
        !          6189:       return;
        !          6190:       
        !          6191: #if 0
        !          6192:       /* FIXME: the XXXX_STMT codes have been removed in GCC2, but
        !          6193:         how are they handled instead? */
        !          6194:     case LET_STMT:
        !          6195:       
        !          6196:       TREE_USED (exp) = 1;
        !          6197:       bc_expand_expr (STMT_BODY (exp));
        !          6198:       return;
        !          6199: #endif
        !          6200:       
        !          6201:     case NOP_EXPR:
        !          6202:     case CONVERT_EXPR:
        !          6203:       
        !          6204:       bc_expand_expr (TREE_OPERAND (exp, 0));
        !          6205:       bc_expand_conversion (TREE_TYPE (TREE_OPERAND (exp, 0)), TREE_TYPE (exp));
        !          6206:       return;
        !          6207:       
        !          6208:     case MODIFY_EXPR:
        !          6209:       
        !          6210:       expand_assignment (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1), 0, 0);
        !          6211:       return;
        !          6212:       
        !          6213:     case ADDR_EXPR:
        !          6214:       
        !          6215:       bc_expand_address (TREE_OPERAND (exp, 0));
        !          6216:       return;
        !          6217:       
        !          6218:     case INDIRECT_REF:
        !          6219:       
        !          6220:       bc_expand_expr (TREE_OPERAND (exp, 0));
        !          6221:       bc_load_memory (TREE_TYPE (exp), TREE_OPERAND (exp, 0));
        !          6222:       return;
        !          6223:       
        !          6224:     case ARRAY_REF:
        !          6225:       
        !          6226:       bc_expand_expr (bc_canonicalize_array_ref (exp));
        !          6227:       return;
        !          6228:       
        !          6229:     case COMPONENT_REF:
        !          6230:       
        !          6231:       bc_expand_component_address (exp);
        !          6232:       
        !          6233:       /* If we have a bitfield, generate a proper load */
        !          6234:       bc_load_memory (TREE_TYPE (TREE_OPERAND (exp, 1)), TREE_OPERAND (exp, 1));
        !          6235:       return;
        !          6236:       
        !          6237:     case COMPOUND_EXPR:
        !          6238:       
        !          6239:       bc_expand_expr (TREE_OPERAND (exp, 0));
        !          6240:       bc_emit_instruction (drop);
        !          6241:       bc_expand_expr (TREE_OPERAND (exp, 1));
        !          6242:       return;
        !          6243:       
        !          6244:     case COND_EXPR:
        !          6245:       
        !          6246:       bc_expand_expr (TREE_OPERAND (exp, 0));
        !          6247:       bc_expand_truth_conversion (TREE_TYPE (TREE_OPERAND (exp, 0)));
        !          6248:       lab = bc_get_bytecode_label ();
        !          6249:       bc_emit_bytecode (xjumpifnot);
        !          6250:       bc_emit_bytecode_labelref (lab);
        !          6251:       
        !          6252: #ifdef DEBUG_PRINT_CODE
        !          6253:       fputc ('\n', stderr);
        !          6254: #endif
        !          6255:       bc_expand_expr (TREE_OPERAND (exp, 1));
        !          6256:       lab1 = bc_get_bytecode_label ();
        !          6257:       bc_emit_bytecode (jump);
        !          6258:       bc_emit_bytecode_labelref (lab1);
        !          6259:       
        !          6260: #ifdef DEBUG_PRINT_CODE
        !          6261:       fputc ('\n', stderr);
        !          6262: #endif
        !          6263:       
        !          6264:       bc_emit_bytecode_labeldef (lab);
        !          6265:       bc_expand_expr (TREE_OPERAND (exp, 2));
        !          6266:       bc_emit_bytecode_labeldef (lab1);
        !          6267:       return;
        !          6268:       
        !          6269:     case TRUTH_ANDIF_EXPR:
        !          6270:       
        !          6271:       opcode = xjumpifnot;
        !          6272:       goto andorif;
        !          6273:       
        !          6274:     case TRUTH_ORIF_EXPR:
        !          6275:       
        !          6276:       opcode = xjumpif;
        !          6277:       goto andorif;
        !          6278:       
        !          6279:     case PLUS_EXPR:
        !          6280:       
        !          6281:       binoptab = optab_plus_expr;
        !          6282:       goto binop;
        !          6283:       
        !          6284:     case MINUS_EXPR:
        !          6285:       
        !          6286:       binoptab = optab_minus_expr;
        !          6287:       goto binop;
        !          6288:       
        !          6289:     case MULT_EXPR:
        !          6290:       
        !          6291:       binoptab = optab_mult_expr;
        !          6292:       goto binop;
        !          6293:       
        !          6294:     case TRUNC_DIV_EXPR:
        !          6295:     case FLOOR_DIV_EXPR:
        !          6296:     case CEIL_DIV_EXPR:
        !          6297:     case ROUND_DIV_EXPR:
        !          6298:     case EXACT_DIV_EXPR:
        !          6299:       
        !          6300:       binoptab = optab_trunc_div_expr;
        !          6301:       goto binop;
        !          6302:       
        !          6303:     case TRUNC_MOD_EXPR:
        !          6304:     case FLOOR_MOD_EXPR:
        !          6305:     case CEIL_MOD_EXPR:
        !          6306:     case ROUND_MOD_EXPR:
        !          6307:       
        !          6308:       binoptab = optab_trunc_mod_expr;
        !          6309:       goto binop;
        !          6310:       
        !          6311:     case FIX_ROUND_EXPR:
        !          6312:     case FIX_FLOOR_EXPR:
        !          6313:     case FIX_CEIL_EXPR:
        !          6314:       abort ();                        /* Not used for C.  */
        !          6315:       
        !          6316:     case FIX_TRUNC_EXPR:
        !          6317:     case FLOAT_EXPR:
        !          6318:     case MAX_EXPR:
        !          6319:     case MIN_EXPR:
        !          6320:     case FFS_EXPR:
        !          6321:     case LROTATE_EXPR:
        !          6322:     case RROTATE_EXPR:
        !          6323:       abort ();                        /* FIXME */
        !          6324:       
        !          6325:     case RDIV_EXPR:
        !          6326:       
        !          6327:       binoptab = optab_rdiv_expr;
        !          6328:       goto binop;
        !          6329:       
        !          6330:     case BIT_AND_EXPR:
        !          6331:       
        !          6332:       binoptab = optab_bit_and_expr;
        !          6333:       goto binop;
        !          6334:       
        !          6335:     case BIT_IOR_EXPR:
        !          6336:       
        !          6337:       binoptab = optab_bit_ior_expr;
        !          6338:       goto binop;
        !          6339:       
        !          6340:     case BIT_XOR_EXPR:
        !          6341:       
        !          6342:       binoptab = optab_bit_xor_expr;
        !          6343:       goto binop;
        !          6344:       
        !          6345:     case LSHIFT_EXPR:
        !          6346:       
        !          6347:       binoptab = optab_lshift_expr;
        !          6348:       goto binop;
        !          6349:       
        !          6350:     case RSHIFT_EXPR:
        !          6351:       
        !          6352:       binoptab = optab_rshift_expr;
        !          6353:       goto binop;
        !          6354:       
        !          6355:     case TRUTH_AND_EXPR:
        !          6356:       
        !          6357:       binoptab = optab_truth_and_expr;
        !          6358:       goto binop;
        !          6359:       
        !          6360:     case TRUTH_OR_EXPR:
        !          6361:       
        !          6362:       binoptab = optab_truth_or_expr;
        !          6363:       goto binop;
        !          6364:       
        !          6365:     case LT_EXPR:
        !          6366:       
        !          6367:       binoptab = optab_lt_expr;
        !          6368:       goto binop;
        !          6369:       
        !          6370:     case LE_EXPR:
        !          6371:       
        !          6372:       binoptab = optab_le_expr;
        !          6373:       goto binop;
        !          6374:       
        !          6375:     case GE_EXPR:
        !          6376:       
        !          6377:       binoptab = optab_ge_expr;
        !          6378:       goto binop;
        !          6379:       
        !          6380:     case GT_EXPR:
        !          6381:       
        !          6382:       binoptab = optab_gt_expr;
        !          6383:       goto binop;
        !          6384:       
        !          6385:     case EQ_EXPR:
        !          6386:       
        !          6387:       binoptab = optab_eq_expr;
        !          6388:       goto binop;
        !          6389:       
        !          6390:     case NE_EXPR:
        !          6391:       
        !          6392:       binoptab = optab_ne_expr;
        !          6393:       goto binop;
        !          6394:       
        !          6395:     case NEGATE_EXPR:
        !          6396:       
        !          6397:       unoptab = optab_negate_expr;
        !          6398:       goto unop;
        !          6399:       
        !          6400:     case BIT_NOT_EXPR:
        !          6401:       
        !          6402:       unoptab = optab_bit_not_expr;
        !          6403:       goto unop;
        !          6404:       
        !          6405:     case TRUTH_NOT_EXPR:
        !          6406:       
        !          6407:       unoptab = optab_truth_not_expr;
        !          6408:       goto unop;
        !          6409:       
        !          6410:     case PREDECREMENT_EXPR:
        !          6411:       
        !          6412:       incroptab = optab_predecrement_expr;
        !          6413:       goto increment;
        !          6414:       
        !          6415:     case PREINCREMENT_EXPR:
        !          6416:       
        !          6417:       incroptab = optab_preincrement_expr;
        !          6418:       goto increment;
        !          6419:       
        !          6420:     case POSTDECREMENT_EXPR:
        !          6421:       
        !          6422:       incroptab = optab_postdecrement_expr;
        !          6423:       goto increment;
        !          6424:       
        !          6425:     case POSTINCREMENT_EXPR:
        !          6426:       
        !          6427:       incroptab = optab_postincrement_expr;
        !          6428:       goto increment;
        !          6429:       
        !          6430:     case CONSTRUCTOR:
        !          6431:       
        !          6432:       bc_expand_constructor (exp);
        !          6433:       return;
        !          6434:       
        !          6435:     case ERROR_MARK:
        !          6436:     case RTL_EXPR:
        !          6437:       
        !          6438:       return;
        !          6439:       
        !          6440:     case BIND_EXPR:
        !          6441:       {
        !          6442:        tree vars = TREE_OPERAND (exp, 0);
        !          6443:        int vars_need_expansion = 0;
        !          6444:        
        !          6445:        /* Need to open a binding contour here because
        !          6446:           if there are any cleanups they most be contained here.  */
        !          6447:        expand_start_bindings (0);
        !          6448:        
        !          6449:        /* Mark the corresponding BLOCK for output.  */
        !          6450:        if (TREE_OPERAND (exp, 2) != 0)
        !          6451:          TREE_USED (TREE_OPERAND (exp, 2)) = 1;
        !          6452:        
        !          6453:        /* If VARS have not yet been expanded, expand them now.  */
        !          6454:        while (vars)
        !          6455:          {
        !          6456:            if (DECL_RTL (vars) == 0)
        !          6457:              {
        !          6458:                vars_need_expansion = 1;
        !          6459:                bc_expand_decl (vars, 0);
        !          6460:              }
        !          6461:            bc_expand_decl_init (vars);
        !          6462:            vars = TREE_CHAIN (vars);
        !          6463:          }
        !          6464:        
        !          6465:        bc_expand_expr (TREE_OPERAND (exp, 1));
        !          6466:        
        !          6467:        expand_end_bindings (TREE_OPERAND (exp, 0), 0, 0);
        !          6468:        
        !          6469:        return;
        !          6470:       }
        !          6471:     }
        !          6472:   
        !          6473:   abort ();
        !          6474:   
        !          6475:  binop:
        !          6476:   
        !          6477:   bc_expand_binary_operation (binoptab, TREE_TYPE (exp),
        !          6478:                              TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1));
        !          6479:   return;
        !          6480:   
        !          6481:   
        !          6482:  unop:
        !          6483:   
        !          6484:   bc_expand_unary_operation (unoptab, TREE_TYPE (exp), TREE_OPERAND (exp, 0));
        !          6485:   return;
        !          6486:   
        !          6487:   
        !          6488:  andorif:
        !          6489:   
        !          6490:   bc_expand_expr (TREE_OPERAND (exp, 0));
        !          6491:   bc_expand_truth_conversion (TREE_TYPE (TREE_OPERAND (exp, 0)));
        !          6492:   lab = bc_get_bytecode_label ();
        !          6493:   
        !          6494:   bc_emit_instruction (duplicate);
        !          6495:   bc_emit_bytecode (opcode);
        !          6496:   bc_emit_bytecode_labelref (lab);
        !          6497:   
        !          6498: #ifdef DEBUG_PRINT_CODE
        !          6499:   fputc ('\n', stderr);
        !          6500: #endif
        !          6501:   
        !          6502:   bc_emit_instruction (drop);
        !          6503:   
        !          6504:   bc_expand_expr (TREE_OPERAND (exp, 1));
        !          6505:   bc_expand_truth_conversion (TREE_TYPE (TREE_OPERAND (exp, 1)));
        !          6506:   bc_emit_bytecode_labeldef (lab);
        !          6507:   return;
        !          6508:   
        !          6509:   
        !          6510:  increment:
        !          6511:   
        !          6512:   type = TREE_TYPE (TREE_OPERAND (exp, 0));
        !          6513:   
        !          6514:   /* Push the quantum.  */
        !          6515:   bc_expand_expr (TREE_OPERAND (exp, 1));
        !          6516:   
        !          6517:   /* Convert it to the lvalue's type.  */
        !          6518:   bc_expand_conversion (TREE_TYPE (TREE_OPERAND (exp, 1)), type);
        !          6519:   
        !          6520:   /* Push the address of the lvalue */
        !          6521:   bc_expand_expr (build1 (ADDR_EXPR, TYPE_POINTER_TO (type), TREE_OPERAND (exp, 0)));
        !          6522:   
        !          6523:   /* Perform actual increment */
        !          6524:   bc_expand_increment (incroptab, type);
        !          6525:   return;
        !          6526: }
        !          6527: 
        !          6528: /* Return the alignment in bits of EXP, a pointer valued expression.
        !          6529:    But don't return more than MAX_ALIGN no matter what.
        !          6530:    The alignment returned is, by default, the alignment of the thing that
        !          6531:    EXP points to (if it is not a POINTER_TYPE, 0 is returned).
        !          6532: 
        !          6533:    Otherwise, look at the expression to see if we can do better, i.e., if the
        !          6534:    expression is actually pointing at an object whose alignment is tighter.  */
        !          6535: 
        !          6536: static int
        !          6537: get_pointer_alignment (exp, max_align)
        !          6538:      tree exp;
        !          6539:      unsigned max_align;
        !          6540: {
        !          6541:   unsigned align, inner;
        !          6542: 
        !          6543:   if (TREE_CODE (TREE_TYPE (exp)) != POINTER_TYPE)
        !          6544:     return 0;
        !          6545: 
        !          6546:   align = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (exp)));
        !          6547:   align = MIN (align, max_align);
        !          6548: 
        !          6549:   while (1)
        !          6550:     {
        !          6551:       switch (TREE_CODE (exp))
        !          6552:        {
        !          6553:        case NOP_EXPR:
        !          6554:        case CONVERT_EXPR:
        !          6555:        case NON_LVALUE_EXPR:
        !          6556:          exp = TREE_OPERAND (exp, 0);
        !          6557:          if (TREE_CODE (TREE_TYPE (exp)) != POINTER_TYPE)
        !          6558:            return align;
        !          6559:          inner = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (exp)));
        !          6560:          inner = MIN (inner, max_align);
        !          6561:          align = MAX (align, inner);
        !          6562:          break;
        !          6563: 
        !          6564:        case PLUS_EXPR:
        !          6565:          /* If sum of pointer + int, restrict our maximum alignment to that
        !          6566:             imposed by the integer.  If not, we can't do any better than
        !          6567:             ALIGN.  */
        !          6568:          if (TREE_CODE (TREE_OPERAND (exp, 1)) != INTEGER_CST)
        !          6569:            return align;
        !          6570: 
        !          6571:          while (((TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)) * BITS_PER_UNIT)
        !          6572:                  & (max_align - 1))
        !          6573:                 != 0)
        !          6574:            max_align >>= 1;
        !          6575: 
        !          6576:          exp = TREE_OPERAND (exp, 0);
        !          6577:          break;
        !          6578: 
        !          6579:        case ADDR_EXPR:
        !          6580:          /* See what we are pointing at and look at its alignment.  */
        !          6581:          exp = TREE_OPERAND (exp, 0);
        !          6582:          if (TREE_CODE (exp) == FUNCTION_DECL)
        !          6583:            align = MAX (align, FUNCTION_BOUNDARY);
        !          6584:          else if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'd')
        !          6585:            align = MAX (align, DECL_ALIGN (exp));
        !          6586: #ifdef CONSTANT_ALIGNMENT
        !          6587:          else if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'c')
        !          6588:            align = CONSTANT_ALIGNMENT (exp, align);
        !          6589: #endif
        !          6590:          return MIN (align, max_align);
        !          6591: 
        !          6592:        default:
        !          6593:          return align;
        !          6594:        }
        !          6595:     }
        !          6596: }
        !          6597: 
        !          6598: /* Return the tree node and offset if a given argument corresponds to
        !          6599:    a string constant.  */
        !          6600: 
        !          6601: static tree
        !          6602: string_constant (arg, ptr_offset)
        !          6603:      tree arg;
        !          6604:      tree *ptr_offset;
        !          6605: {
        !          6606:   STRIP_NOPS (arg);
        !          6607: 
        !          6608:   if (TREE_CODE (arg) == ADDR_EXPR
        !          6609:       && TREE_CODE (TREE_OPERAND (arg, 0)) == STRING_CST)
        !          6610:     {
        !          6611:       *ptr_offset = integer_zero_node;
        !          6612:       return TREE_OPERAND (arg, 0);
        !          6613:     }
        !          6614:   else if (TREE_CODE (arg) == PLUS_EXPR)
        !          6615:     {
        !          6616:       tree arg0 = TREE_OPERAND (arg, 0);
        !          6617:       tree arg1 = TREE_OPERAND (arg, 1);
        !          6618: 
        !          6619:       STRIP_NOPS (arg0);
        !          6620:       STRIP_NOPS (arg1);
        !          6621: 
        !          6622:       if (TREE_CODE (arg0) == ADDR_EXPR
        !          6623:          && TREE_CODE (TREE_OPERAND (arg0, 0)) == STRING_CST)
        !          6624:        {
        !          6625:          *ptr_offset = arg1;
        !          6626:          return TREE_OPERAND (arg0, 0);
        !          6627:        }
        !          6628:       else if (TREE_CODE (arg1) == ADDR_EXPR
        !          6629:               && TREE_CODE (TREE_OPERAND (arg1, 0)) == STRING_CST)
        !          6630:        {
        !          6631:          *ptr_offset = arg0;
        !          6632:          return TREE_OPERAND (arg1, 0);
        !          6633:        }
        !          6634:     }
        !          6635: 
        !          6636:   return 0;
        !          6637: }
        !          6638: 
        !          6639: /* Compute the length of a C string.  TREE_STRING_LENGTH is not the right
        !          6640:    way, because it could contain a zero byte in the middle.
        !          6641:    TREE_STRING_LENGTH is the size of the character array, not the string.
        !          6642: 
        !          6643:    Unfortunately, string_constant can't access the values of const char
        !          6644:    arrays with initializers, so neither can we do so here.  */
        !          6645: 
        !          6646: static tree
        !          6647: c_strlen (src)
        !          6648:      tree src;
        !          6649: {
        !          6650:   tree offset_node;
        !          6651:   int offset, max;
        !          6652:   char *ptr;
        !          6653: 
        !          6654:   src = string_constant (src, &offset_node);
        !          6655:   if (src == 0)
        !          6656:     return 0;
        !          6657:   max = TREE_STRING_LENGTH (src);
        !          6658:   ptr = TREE_STRING_POINTER (src);
        !          6659:   if (offset_node && TREE_CODE (offset_node) != INTEGER_CST)
        !          6660:     {
        !          6661:       /* If the string has an internal zero byte (e.g., "foo\0bar"), we can't
        !          6662:         compute the offset to the following null if we don't know where to
        !          6663:         start searching for it.  */
        !          6664:       int i;
        !          6665:       for (i = 0; i < max; i++)
        !          6666:        if (ptr[i] == 0)
        !          6667:          return 0;
        !          6668:       /* We don't know the starting offset, but we do know that the string
        !          6669:         has no internal zero bytes.  We can assume that the offset falls
        !          6670:         within the bounds of the string; otherwise, the programmer deserves
        !          6671:         what he gets.  Subtract the offset from the length of the string,
        !          6672:         and return that.  */
        !          6673:       /* This would perhaps not be valid if we were dealing with named
        !          6674:          arrays in addition to literal string constants.  */
        !          6675:       return size_binop (MINUS_EXPR, size_int (max), offset_node);
        !          6676:     }
        !          6677: 
        !          6678:   /* We have a known offset into the string.  Start searching there for
        !          6679:      a null character.  */
        !          6680:   if (offset_node == 0)
        !          6681:     offset = 0;
        !          6682:   else
        !          6683:     {
        !          6684:       /* Did we get a long long offset?  If so, punt.  */
        !          6685:       if (TREE_INT_CST_HIGH (offset_node) != 0)
        !          6686:        return 0;
        !          6687:       offset = TREE_INT_CST_LOW (offset_node);
        !          6688:     }
        !          6689:   /* If the offset is known to be out of bounds, warn, and call strlen at
        !          6690:      runtime.  */
        !          6691:   if (offset < 0 || offset > max)
        !          6692:     {
        !          6693:       warning ("offset outside bounds of constant string");
        !          6694:       return 0;
        !          6695:     }
        !          6696:   /* Use strlen to search for the first zero byte.  Since any strings
        !          6697:      constructed with build_string will have nulls appended, we win even
        !          6698:      if we get handed something like (char[4])"abcd".
        !          6699: 
        !          6700:      Since OFFSET is our starting index into the string, no further
        !          6701:      calculation is needed.  */
        !          6702:   return size_int (strlen (ptr + offset));
        !          6703: }
        !          6704: 
        !          6705: /* Expand an expression EXP that calls a built-in function,
        !          6706:    with result going to TARGET if that's convenient
        !          6707:    (and in mode MODE if that's convenient).
        !          6708:    SUBTARGET may be used as the target for computing one of EXP's operands.
        !          6709:    IGNORE is nonzero if the value is to be ignored.  */
        !          6710: 
        !          6711: static rtx
        !          6712: expand_builtin (exp, target, subtarget, mode, ignore)
        !          6713:      tree exp;
        !          6714:      rtx target;
        !          6715:      rtx subtarget;
        !          6716:      enum machine_mode mode;
        !          6717:      int ignore;
        !          6718: {
        !          6719:   tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
        !          6720:   tree arglist = TREE_OPERAND (exp, 1);
        !          6721:   rtx op0;
        !          6722:   rtx lab1, insns;
        !          6723:   enum machine_mode value_mode = TYPE_MODE (TREE_TYPE (exp));
        !          6724:   optab builtin_optab;
        !          6725: 
        !          6726:   switch (DECL_FUNCTION_CODE (fndecl))
        !          6727:     {
        !          6728:     case BUILT_IN_ABS:
        !          6729:     case BUILT_IN_LABS:
        !          6730:     case BUILT_IN_FABS:
        !          6731:       /* build_function_call changes these into ABS_EXPR.  */
        !          6732:       abort ();
        !          6733: 
        !          6734:     case BUILT_IN_SIN:
        !          6735:     case BUILT_IN_COS:
        !          6736:     case BUILT_IN_FSQRT:
        !          6737:       /* If not optimizing, call the library function.  */
        !          6738:       if (! optimize)
        !          6739:        break;
        !          6740: 
        !          6741:       if (arglist == 0
        !          6742:          /* Arg could be wrong type if user redeclared this fcn wrong.  */
        !          6743:          || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != REAL_TYPE)
        !          6744:        break;
        !          6745: 
        !          6746:       /* Stabilize and compute the argument.  */
        !          6747:       if (TREE_CODE (TREE_VALUE (arglist)) != VAR_DECL
        !          6748:          && TREE_CODE (TREE_VALUE (arglist)) != PARM_DECL)
        !          6749:        {
        !          6750:          exp = copy_node (exp);
        !          6751:          arglist = copy_node (arglist);
        !          6752:          TREE_OPERAND (exp, 1) = arglist;
        !          6753:          TREE_VALUE (arglist) = save_expr (TREE_VALUE (arglist));
        !          6754:        }
        !          6755:       op0 = expand_expr (TREE_VALUE (arglist), subtarget, VOIDmode, 0);
        !          6756: 
        !          6757:       /* Make a suitable register to place result in.  */
        !          6758:       target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
        !          6759: 
        !          6760:       emit_queue ();
        !          6761:       start_sequence ();
        !          6762: 
        !          6763:       switch (DECL_FUNCTION_CODE (fndecl))
        !          6764:        {
        !          6765:        case BUILT_IN_SIN:
        !          6766:          builtin_optab = sin_optab; break;
        !          6767:        case BUILT_IN_COS:
        !          6768:          builtin_optab = cos_optab; break;
        !          6769:        case BUILT_IN_FSQRT:
        !          6770:          builtin_optab = sqrt_optab; break;
        !          6771:        default:
        !          6772:          abort ();
        !          6773:        }
        !          6774: 
        !          6775:       /* Compute into TARGET.
        !          6776:         Set TARGET to wherever the result comes back.  */
        !          6777:       target = expand_unop (TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist))),
        !          6778:                            builtin_optab, op0, target, 0);
        !          6779: 
        !          6780:       /* If we were unable to expand via the builtin, stop the
        !          6781:         sequence (without outputting the insns) and break, causing
        !          6782:         a call the the library function.  */
        !          6783:       if (target == 0)
        !          6784:        {
        !          6785:          end_sequence ();
        !          6786:          break;
        !          6787:         }
        !          6788: 
        !          6789:       /* Check the results by default.  But if flag_fast_math is turned on,
        !          6790:         then assume sqrt will always be called with valid arguments.  */
        !          6791: 
        !          6792:       if (! flag_fast_math)
        !          6793:        {
        !          6794:          /* Don't define the builtin FP instructions
        !          6795:             if your machine is not IEEE.  */
        !          6796:          if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT)
        !          6797:            abort ();
        !          6798: 
        !          6799:          lab1 = gen_label_rtx ();
        !          6800: 
        !          6801:          /* Test the result; if it is NaN, set errno=EDOM because
        !          6802:             the argument was not in the domain.  */
        !          6803:          emit_cmp_insn (target, target, EQ, 0, GET_MODE (target), 0, 0);
        !          6804:          emit_jump_insn (gen_beq (lab1));
        !          6805: 
        !          6806: #if TARGET_EDOM
        !          6807:          {
        !          6808: #ifdef GEN_ERRNO_RTX
        !          6809:            rtx errno_rtx = GEN_ERRNO_RTX;
        !          6810: #else
        !          6811:            rtx errno_rtx
        !          6812:              = gen_rtx (MEM, word_mode, gen_rtx (SYMBOL_REF, Pmode, "*errno"));
        !          6813: #endif
        !          6814: 
        !          6815:            emit_move_insn (errno_rtx, GEN_INT (TARGET_EDOM));
        !          6816:          }
        !          6817: #else
        !          6818:          /* We can't set errno=EDOM directly; let the library call do it.
        !          6819:             Pop the arguments right away in case the call gets deleted. */
        !          6820:          NO_DEFER_POP;
        !          6821:          expand_call (exp, target, 0);
        !          6822:          OK_DEFER_POP;
        !          6823: #endif
        !          6824: 
        !          6825:          emit_label (lab1);
        !          6826:        }
        !          6827: 
        !          6828:       /* Output the entire sequence. */
        !          6829:       insns = get_insns ();
        !          6830:       end_sequence ();
        !          6831:       emit_insns (insns);
        !          6832:  
        !          6833:       return target;
        !          6834: 
        !          6835:       /* __builtin_apply_args returns block of memory allocated on
        !          6836:         the stack into which is stored the arg pointer, structure
        !          6837:         value address, static chain, and all the registers that might
        !          6838:         possibly be used in performing a function call.  The code is
        !          6839:         moved to the start of the function so the incoming values are
        !          6840:         saved.  */
        !          6841:     case BUILT_IN_APPLY_ARGS:
        !          6842:       /* Don't do __builtin_apply_args more than once in a function.
        !          6843:         Save the result of the first call and reuse it.  */
        !          6844:       if (apply_args_value != 0)
        !          6845:        return apply_args_value;
        !          6846:       {
        !          6847:        /* When this function is called, it means that registers must be
        !          6848:           saved on entry to this function.  So we migrate the
        !          6849:           call to the first insn of this function.  */
        !          6850:        rtx temp;
        !          6851:        rtx seq;
        !          6852: 
        !          6853:        start_sequence ();
        !          6854:        temp = expand_builtin_apply_args ();
        !          6855:        seq = get_insns ();
        !          6856:        end_sequence ();
        !          6857: 
        !          6858:        apply_args_value = temp;
        !          6859: 
        !          6860:        /* Put the sequence after the NOTE that starts the function.
        !          6861:           If this is inside a SEQUENCE, make the outer-level insn
        !          6862:           chain current, so the code is placed at the start of the
        !          6863:           function.  */
        !          6864:        push_topmost_sequence ();
        !          6865:        emit_insns_before (seq, NEXT_INSN (get_insns ()));
        !          6866:        pop_topmost_sequence ();
        !          6867:        return temp;
        !          6868:       }
        !          6869: 
        !          6870:       /* __builtin_apply (FUNCTION, ARGUMENTS, ARGSIZE) invokes
        !          6871:         FUNCTION with a copy of the parameters described by
        !          6872:         ARGUMENTS, and ARGSIZE.  It returns a block of memory
        !          6873:         allocated on the stack into which is stored all the registers
        !          6874:         that might possibly be used for returning the result of a
        !          6875:         function.  ARGUMENTS is the value returned by
        !          6876:         __builtin_apply_args.  ARGSIZE is the number of bytes of
        !          6877:         arguments that must be copied.  ??? How should this value be
        !          6878:         computed?  We'll also need a safe worst case value for varargs
        !          6879:         functions.  */
        !          6880:     case BUILT_IN_APPLY:
        !          6881:       if (arglist == 0
        !          6882:          /* Arg could be non-pointer if user redeclared this fcn wrong.  */
        !          6883:          || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
        !          6884:          || TREE_CHAIN (arglist) == 0
        !          6885:          || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != POINTER_TYPE
        !          6886:          || TREE_CHAIN (TREE_CHAIN (arglist)) == 0
        !          6887:          || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))))) != INTEGER_TYPE)
        !          6888:        return const0_rtx;
        !          6889:       else
        !          6890:        {
        !          6891:          int i;
        !          6892:          tree t;
        !          6893:          rtx ops[3];
        !          6894: 
        !          6895:          for (t = arglist, i = 0; t; t = TREE_CHAIN (t), i++)
        !          6896:            ops[i] = expand_expr (TREE_VALUE (t), NULL_RTX, VOIDmode, 0);
        !          6897: 
        !          6898:          return expand_builtin_apply (ops[0], ops[1], ops[2]);
        !          6899:        }
        !          6900: 
        !          6901:       /* __builtin_return (RESULT) causes the function to return the
        !          6902:         value described by RESULT.  RESULT is address of the block of
        !          6903:         memory returned by __builtin_apply.  */
        !          6904:     case BUILT_IN_RETURN:
        !          6905:       if (arglist
        !          6906:          /* Arg could be non-pointer if user redeclared this fcn wrong.  */
        !          6907:          && TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) == POINTER_TYPE)
        !          6908:        expand_builtin_return (expand_expr (TREE_VALUE (arglist),
        !          6909:                                            NULL_RTX, VOIDmode, 0));
        !          6910:       return const0_rtx;
        !          6911: 
        !          6912:     case BUILT_IN_SAVEREGS:
        !          6913:       /* Don't do __builtin_saveregs more than once in a function.
        !          6914:         Save the result of the first call and reuse it.  */
        !          6915:       if (saveregs_value != 0)
        !          6916:        return saveregs_value;
        !          6917:       {
        !          6918:        /* When this function is called, it means that registers must be
        !          6919:           saved on entry to this function.  So we migrate the
        !          6920:           call to the first insn of this function.  */
        !          6921:        rtx temp;
        !          6922:        rtx seq;
        !          6923:        rtx valreg, saved_valreg;
        !          6924: 
        !          6925:        /* Now really call the function.  `expand_call' does not call
        !          6926:           expand_builtin, so there is no danger of infinite recursion here.  */
        !          6927:        start_sequence ();
        !          6928: 
        !          6929: #ifdef EXPAND_BUILTIN_SAVEREGS
        !          6930:        /* Do whatever the machine needs done in this case.  */
        !          6931:        temp = EXPAND_BUILTIN_SAVEREGS (arglist);
        !          6932: #else
        !          6933:        /* The register where the function returns its value
        !          6934:           is likely to have something else in it, such as an argument.
        !          6935:           So preserve that register around the call.  */
        !          6936:        if (value_mode != VOIDmode)
        !          6937:          {
        !          6938:            valreg = hard_libcall_value (value_mode);
        !          6939:            saved_valreg = gen_reg_rtx (value_mode);
        !          6940:            emit_move_insn (saved_valreg, valreg);
        !          6941:          }
        !          6942: 
        !          6943:        /* Generate the call, putting the value in a pseudo.  */
        !          6944:        temp = expand_call (exp, target, ignore);
        !          6945: 
        !          6946:        if (value_mode != VOIDmode)
        !          6947:          emit_move_insn (valreg, saved_valreg);
        !          6948: #endif
        !          6949: 
        !          6950:        seq = get_insns ();
        !          6951:        end_sequence ();
        !          6952: 
        !          6953:        saveregs_value = temp;
        !          6954: 
        !          6955:        /* Put the sequence after the NOTE that starts the function.
        !          6956:           If this is inside a SEQUENCE, make the outer-level insn
        !          6957:           chain current, so the code is placed at the start of the
        !          6958:           function.  */
        !          6959:        push_topmost_sequence ();
        !          6960:        emit_insns_before (seq, NEXT_INSN (get_insns ()));
        !          6961:        pop_topmost_sequence ();
        !          6962:        return temp;
        !          6963:       }
        !          6964: 
        !          6965:       /* __builtin_args_info (N) returns word N of the arg space info
        !          6966:         for the current function.  The number and meanings of words
        !          6967:         is controlled by the definition of CUMULATIVE_ARGS.  */
        !          6968:     case BUILT_IN_ARGS_INFO:
        !          6969:       {
        !          6970:        int nwords = sizeof (CUMULATIVE_ARGS) / sizeof (int);
        !          6971:        int i;
        !          6972:        int *word_ptr = (int *) &current_function_args_info;
        !          6973:        tree type, elts, result;
        !          6974: 
        !          6975:        if (sizeof (CUMULATIVE_ARGS) % sizeof (int) != 0)
        !          6976:          fatal ("CUMULATIVE_ARGS type defined badly; see %s, line %d",
        !          6977:                 __FILE__, __LINE__);
        !          6978: 
        !          6979:        if (arglist != 0)
        !          6980:          {
        !          6981:            tree arg = TREE_VALUE (arglist);
        !          6982:            if (TREE_CODE (arg) != INTEGER_CST)
        !          6983:              error ("argument of `__builtin_args_info' must be constant");
        !          6984:            else
        !          6985:              {
        !          6986:                int wordnum = TREE_INT_CST_LOW (arg);
        !          6987: 
        !          6988:                if (wordnum < 0 || wordnum >= nwords || TREE_INT_CST_HIGH (arg))
        !          6989:                  error ("argument of `__builtin_args_info' out of range");
        !          6990:                else
        !          6991:                  return GEN_INT (word_ptr[wordnum]);
        !          6992:              }
        !          6993:          }
        !          6994:        else
        !          6995:          error ("missing argument in `__builtin_args_info'");
        !          6996: 
        !          6997:        return const0_rtx;
        !          6998: 
        !          6999: #if 0
        !          7000:        for (i = 0; i < nwords; i++)
        !          7001:          elts = tree_cons (NULL_TREE, build_int_2 (word_ptr[i], 0));
        !          7002: 
        !          7003:        type = build_array_type (integer_type_node,
        !          7004:                                 build_index_type (build_int_2 (nwords, 0)));
        !          7005:        result = build (CONSTRUCTOR, type, NULL_TREE, nreverse (elts));
        !          7006:        TREE_CONSTANT (result) = 1;
        !          7007:        TREE_STATIC (result) = 1;
        !          7008:        result = build (INDIRECT_REF, build_pointer_type (type), result);
        !          7009:        TREE_CONSTANT (result) = 1;
        !          7010:        return expand_expr (result, NULL_RTX, VOIDmode, 0);
        !          7011: #endif
        !          7012:       }
        !          7013: 
        !          7014:       /* Return the address of the first anonymous stack arg.  */
        !          7015:     case BUILT_IN_NEXT_ARG:
        !          7016:       {
        !          7017:        tree fntype = TREE_TYPE (current_function_decl);
        !          7018:        if (!(TYPE_ARG_TYPES (fntype) != 0
        !          7019:              && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
        !          7020:                  != void_type_node)))
        !          7021:          {
        !          7022:            error ("`va_start' used in function with fixed args");
        !          7023:            return const0_rtx;
        !          7024:          }
        !          7025:       }
        !          7026: 
        !          7027:       return expand_binop (Pmode, add_optab,
        !          7028:                           current_function_internal_arg_pointer,
        !          7029:                           current_function_arg_offset_rtx,
        !          7030:                           NULL_RTX, 0, OPTAB_LIB_WIDEN);
        !          7031: 
        !          7032:     case BUILT_IN_CLASSIFY_TYPE:
        !          7033:       if (arglist != 0)
        !          7034:        {
        !          7035:          tree type = TREE_TYPE (TREE_VALUE (arglist));
        !          7036:          enum tree_code code = TREE_CODE (type);
        !          7037:          if (code == VOID_TYPE)
        !          7038:            return GEN_INT (void_type_class);
        !          7039:          if (code == INTEGER_TYPE)
        !          7040:            return GEN_INT (integer_type_class);
        !          7041:          if (code == CHAR_TYPE)
        !          7042:            return GEN_INT (char_type_class);
        !          7043:          if (code == ENUMERAL_TYPE)
        !          7044:            return GEN_INT (enumeral_type_class);
        !          7045:          if (code == BOOLEAN_TYPE)
        !          7046:            return GEN_INT (boolean_type_class);
        !          7047:          if (code == POINTER_TYPE)
        !          7048:            return GEN_INT (pointer_type_class);
        !          7049:          if (code == REFERENCE_TYPE)
        !          7050:            return GEN_INT (reference_type_class);
        !          7051:          if (code == OFFSET_TYPE)
        !          7052:            return GEN_INT (offset_type_class);
        !          7053:          if (code == REAL_TYPE)
        !          7054:            return GEN_INT (real_type_class);
        !          7055:          if (code == COMPLEX_TYPE)
        !          7056:            return GEN_INT (complex_type_class);
        !          7057:          if (code == FUNCTION_TYPE)
        !          7058:            return GEN_INT (function_type_class);
        !          7059:          if (code == METHOD_TYPE)
        !          7060:            return GEN_INT (method_type_class);
        !          7061:          if (code == RECORD_TYPE)
        !          7062:            return GEN_INT (record_type_class);
        !          7063:          if (code == UNION_TYPE || code == QUAL_UNION_TYPE)
        !          7064:            return GEN_INT (union_type_class);
        !          7065:          if (code == ARRAY_TYPE)
        !          7066:            return GEN_INT (array_type_class);
        !          7067:          if (code == STRING_TYPE)
        !          7068:            return GEN_INT (string_type_class);
        !          7069:          if (code == SET_TYPE)
        !          7070:            return GEN_INT (set_type_class);
        !          7071:          if (code == FILE_TYPE)
        !          7072:            return GEN_INT (file_type_class);
        !          7073:          if (code == LANG_TYPE)
        !          7074:            return GEN_INT (lang_type_class);
        !          7075:        }
        !          7076:       return GEN_INT (no_type_class);
        !          7077: 
        !          7078:     case BUILT_IN_CONSTANT_P:
        !          7079:       if (arglist == 0)
        !          7080:        return const0_rtx;
        !          7081:       else
        !          7082:        return (TREE_CODE_CLASS (TREE_CODE (TREE_VALUE (arglist))) == 'c'
        !          7083:                ? const1_rtx : const0_rtx);
        !          7084: 
        !          7085:     case BUILT_IN_FRAME_ADDRESS:
        !          7086:       /* The argument must be a nonnegative integer constant.
        !          7087:         It counts the number of frames to scan up the stack.
        !          7088:         The value is the address of that frame.  */
        !          7089:     case BUILT_IN_RETURN_ADDRESS:
        !          7090:       /* The argument must be a nonnegative integer constant.
        !          7091:         It counts the number of frames to scan up the stack.
        !          7092:         The value is the return address saved in that frame.  */
        !          7093:       if (arglist == 0)
        !          7094:        /* Warning about missing arg was already issued.  */
        !          7095:        return const0_rtx;
        !          7096:       else if (TREE_CODE (TREE_VALUE (arglist)) != INTEGER_CST)
        !          7097:        {
        !          7098:          error ("invalid arg to `__builtin_return_address'");
        !          7099:          return const0_rtx;
        !          7100:        }
        !          7101:       else if (tree_int_cst_lt (TREE_VALUE (arglist), integer_zero_node))
        !          7102:        {
        !          7103:          error ("invalid arg to `__builtin_return_address'");
        !          7104:          return const0_rtx;
        !          7105:        }
        !          7106:       else
        !          7107:        {
        !          7108:          int count = TREE_INT_CST_LOW (TREE_VALUE (arglist)); 
        !          7109:          rtx tem = frame_pointer_rtx;
        !          7110:          int i;
        !          7111: 
        !          7112:          /* Some machines need special handling before we can access arbitrary
        !          7113:             frames.  For example, on the sparc, we must first flush all
        !          7114:             register windows to the stack.  */
        !          7115: #ifdef SETUP_FRAME_ADDRESSES
        !          7116:          SETUP_FRAME_ADDRESSES ();
        !          7117: #endif
        !          7118: 
        !          7119:          /* On the sparc, the return address is not in the frame, it is
        !          7120:             in a register.  There is no way to access it off of the current
        !          7121:             frame pointer, but it can be accessed off the previous frame
        !          7122:             pointer by reading the value from the register window save
        !          7123:             area.  */
        !          7124: #ifdef RETURN_ADDR_IN_PREVIOUS_FRAME
        !          7125:          if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_RETURN_ADDRESS)
        !          7126:            count--;
        !          7127: #endif
        !          7128: 
        !          7129:          /* Scan back COUNT frames to the specified frame.  */
        !          7130:          for (i = 0; i < count; i++)
        !          7131:            {
        !          7132:              /* Assume the dynamic chain pointer is in the word that
        !          7133:                 the frame address points to, unless otherwise specified.  */
        !          7134: #ifdef DYNAMIC_CHAIN_ADDRESS
        !          7135:              tem = DYNAMIC_CHAIN_ADDRESS (tem);
        !          7136: #endif
        !          7137:              tem = memory_address (Pmode, tem);
        !          7138:              tem = copy_to_reg (gen_rtx (MEM, Pmode, tem));
        !          7139:            }
        !          7140: 
        !          7141:          /* For __builtin_frame_address, return what we've got.  */
        !          7142:          if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
        !          7143:            return tem;
        !          7144: 
        !          7145:          /* For __builtin_return_address,
        !          7146:             Get the return address from that frame.  */
        !          7147: #ifdef RETURN_ADDR_RTX
        !          7148:          return RETURN_ADDR_RTX (count, tem);
        !          7149: #else
        !          7150:          tem = memory_address (Pmode,
        !          7151:                                plus_constant (tem, GET_MODE_SIZE (Pmode)));
        !          7152:          return copy_to_reg (gen_rtx (MEM, Pmode, tem));
        !          7153: #endif
        !          7154:        }
        !          7155: 
        !          7156:     case BUILT_IN_ALLOCA:
        !          7157:       if (arglist == 0
        !          7158:          /* Arg could be non-integer if user redeclared this fcn wrong.  */
        !          7159:          || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE)
        !          7160:        break;
        !          7161:       current_function_calls_alloca = 1;
        !          7162:       /* Compute the argument.  */
        !          7163:       op0 = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0);
        !          7164: 
        !          7165:       /* Allocate the desired space.  */
        !          7166:       target = allocate_dynamic_stack_space (op0, target, BITS_PER_UNIT);
        !          7167: 
        !          7168:       /* Record the new stack level for nonlocal gotos.  */
        !          7169:       if (nonlocal_goto_handler_slot != 0)
        !          7170:        emit_stack_save (SAVE_NONLOCAL, &nonlocal_goto_stack_level, NULL_RTX);
        !          7171:       return target;
        !          7172: 
        !          7173:     case BUILT_IN_FFS:
        !          7174:       /* If not optimizing, call the library function.  */
        !          7175:       if (!optimize)
        !          7176:        break;
        !          7177: 
        !          7178:       if (arglist == 0
        !          7179:          /* Arg could be non-integer if user redeclared this fcn wrong.  */
        !          7180:          || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE)
        !          7181:        break;
        !          7182: 
        !          7183:       /* Compute the argument.  */
        !          7184:       op0 = expand_expr (TREE_VALUE (arglist), subtarget, VOIDmode, 0);
        !          7185:       /* Compute ffs, into TARGET if possible.
        !          7186:         Set TARGET to wherever the result comes back.  */
        !          7187:       target = expand_unop (TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist))),
        !          7188:                            ffs_optab, op0, target, 1);
        !          7189:       if (target == 0)
        !          7190:        abort ();
        !          7191:       return target;
        !          7192: 
        !          7193:     case BUILT_IN_STRLEN:
        !          7194:       /* If not optimizing, call the library function.  */
        !          7195:       if (!optimize)
        !          7196:        break;
        !          7197: 
        !          7198:       if (arglist == 0
        !          7199:          /* Arg could be non-pointer if user redeclared this fcn wrong.  */
        !          7200:          || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE)
        !          7201:        break;
        !          7202:       else
        !          7203:        {
        !          7204:          tree src = TREE_VALUE (arglist);
        !          7205:          tree len = c_strlen (src);
        !          7206: 
        !          7207:          int align
        !          7208:            = get_pointer_alignment (src, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
        !          7209: 
        !          7210:          rtx result, src_rtx, char_rtx;
        !          7211:          enum machine_mode insn_mode = value_mode, char_mode;
        !          7212:          enum insn_code icode;
        !          7213: 
        !          7214:          /* If the length is known, just return it. */
        !          7215:          if (len != 0)
        !          7216:            return expand_expr (len, target, mode, 0);
        !          7217: 
        !          7218:          /* If SRC is not a pointer type, don't do this operation inline. */
        !          7219:          if (align == 0)
        !          7220:            break;
        !          7221: 
        !          7222:          /* Call a function if we can't compute strlen in the right mode. */
        !          7223: 
        !          7224:          while (insn_mode != VOIDmode)
        !          7225:            {
        !          7226:              icode = strlen_optab->handlers[(int) insn_mode].insn_code;
        !          7227:              if (icode != CODE_FOR_nothing)
        !          7228:                break;
        !          7229: 
        !          7230:              insn_mode = GET_MODE_WIDER_MODE (insn_mode);
        !          7231:            }
        !          7232:          if (insn_mode == VOIDmode)
        !          7233:            break;
        !          7234: 
        !          7235:          /* Make a place to write the result of the instruction.  */
        !          7236:          result = target;
        !          7237:          if (! (result != 0
        !          7238:                 && GET_CODE (result) == REG
        !          7239:                 && GET_MODE (result) == insn_mode
        !          7240:                 && REGNO (result) >= FIRST_PSEUDO_REGISTER))
        !          7241:            result = gen_reg_rtx (insn_mode);
        !          7242: 
        !          7243:          /* Make sure the operands are acceptable to the predicates.  */
        !          7244: 
        !          7245:          if (! (*insn_operand_predicate[(int)icode][0]) (result, insn_mode))
        !          7246:            result = gen_reg_rtx (insn_mode);
        !          7247: 
        !          7248:          src_rtx = memory_address (BLKmode,
        !          7249:                                    expand_expr (src, NULL_RTX, Pmode,
        !          7250:                                                 EXPAND_NORMAL));
        !          7251:          if (! (*insn_operand_predicate[(int)icode][1]) (src_rtx, Pmode))
        !          7252:            src_rtx = copy_to_mode_reg (Pmode, src_rtx);
        !          7253: 
        !          7254:          char_rtx = const0_rtx;
        !          7255:          char_mode = insn_operand_mode[(int)icode][2];
        !          7256:          if (! (*insn_operand_predicate[(int)icode][2]) (char_rtx, char_mode))
        !          7257:            char_rtx = copy_to_mode_reg (char_mode, char_rtx);
        !          7258: 
        !          7259:          emit_insn (GEN_FCN (icode) (result,
        !          7260:                                      gen_rtx (MEM, BLKmode, src_rtx),
        !          7261:                                      char_rtx, GEN_INT (align)));
        !          7262: 
        !          7263:          /* Return the value in the proper mode for this function.  */
        !          7264:          if (GET_MODE (result) == value_mode)
        !          7265:            return result;
        !          7266:          else if (target != 0)
        !          7267:            {
        !          7268:              convert_move (target, result, 0);
        !          7269:              return target;
        !          7270:            }
        !          7271:          else
        !          7272:            return convert_to_mode (value_mode, result, 0);
        !          7273:        }
        !          7274: 
        !          7275:     case BUILT_IN_STRCPY:
        !          7276:       /* If not optimizing, call the library function.  */
        !          7277:       if (!optimize)
        !          7278:        break;
        !          7279: 
        !          7280:       if (arglist == 0
        !          7281:          /* Arg could be non-pointer if user redeclared this fcn wrong.  */
        !          7282:          || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
        !          7283:          || TREE_CHAIN (arglist) == 0
        !          7284:          || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != POINTER_TYPE)
        !          7285:        break;
        !          7286:       else
        !          7287:        {
        !          7288:          tree len = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)));
        !          7289: 
        !          7290:          if (len == 0)
        !          7291:            break;
        !          7292: 
        !          7293:          len = size_binop (PLUS_EXPR, len, integer_one_node);
        !          7294: 
        !          7295:          chainon (arglist, build_tree_list (NULL_TREE, len));
        !          7296:        }
        !          7297: 
        !          7298:       /* Drops in.  */
        !          7299:     case BUILT_IN_MEMCPY:
        !          7300:       /* If not optimizing, call the library function.  */
        !          7301:       if (!optimize)
        !          7302:        break;
        !          7303: 
        !          7304:       if (arglist == 0
        !          7305:          /* Arg could be non-pointer if user redeclared this fcn wrong.  */
        !          7306:          || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
        !          7307:          || TREE_CHAIN (arglist) == 0
        !          7308:          || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != POINTER_TYPE
        !          7309:          || TREE_CHAIN (TREE_CHAIN (arglist)) == 0
        !          7310:          || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))))) != INTEGER_TYPE)
        !          7311:        break;
        !          7312:       else
        !          7313:        {
        !          7314:          tree dest = TREE_VALUE (arglist);
        !          7315:          tree src = TREE_VALUE (TREE_CHAIN (arglist));
        !          7316:          tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
        !          7317: 
        !          7318:          int src_align
        !          7319:            = get_pointer_alignment (src, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
        !          7320:          int dest_align
        !          7321:            = get_pointer_alignment (dest, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
        !          7322:          rtx dest_rtx, dest_mem, src_mem;
        !          7323: 
        !          7324:          /* If either SRC or DEST is not a pointer type, don't do
        !          7325:             this operation in-line.  */
        !          7326:          if (src_align == 0 || dest_align == 0)
        !          7327:            {
        !          7328:              if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STRCPY)
        !          7329:                TREE_CHAIN (TREE_CHAIN (arglist)) = 0;
        !          7330:              break;
        !          7331:            }
        !          7332: 
        !          7333:          dest_rtx = expand_expr (dest, NULL_RTX, Pmode, EXPAND_NORMAL);
        !          7334:          dest_mem = gen_rtx (MEM, BLKmode,
        !          7335:                              memory_address (BLKmode, dest_rtx));
        !          7336:          src_mem = gen_rtx (MEM, BLKmode,
        !          7337:                             memory_address (BLKmode,
        !          7338:                                             expand_expr (src, NULL_RTX,
        !          7339:                                                          Pmode,
        !          7340:                                                          EXPAND_NORMAL)));
        !          7341: 
        !          7342:          /* Copy word part most expediently.  */
        !          7343:          emit_block_move (dest_mem, src_mem,
        !          7344:                           expand_expr (len, NULL_RTX, VOIDmode, 0),
        !          7345:                           MIN (src_align, dest_align));
        !          7346:          return dest_rtx;
        !          7347:        }
        !          7348: 
        !          7349: /* These comparison functions need an instruction that returns an actual
        !          7350:    index.  An ordinary compare that just sets the condition codes
        !          7351:    is not enough.  */
        !          7352: #ifdef HAVE_cmpstrsi
        !          7353:     case BUILT_IN_STRCMP:
        !          7354:       /* If not optimizing, call the library function.  */
        !          7355:       if (!optimize)
        !          7356:        break;
        !          7357: 
        !          7358:       if (arglist == 0
        !          7359:          /* Arg could be non-pointer if user redeclared this fcn wrong.  */
        !          7360:          || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
        !          7361:          || TREE_CHAIN (arglist) == 0
        !          7362:          || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != POINTER_TYPE)
        !          7363:        break;
        !          7364:       else if (!HAVE_cmpstrsi)
        !          7365:        break;
        !          7366:       {
        !          7367:        tree arg1 = TREE_VALUE (arglist);
        !          7368:        tree arg2 = TREE_VALUE (TREE_CHAIN (arglist));
        !          7369:        tree offset;
        !          7370:        tree len, len2;
        !          7371: 
        !          7372:        len = c_strlen (arg1);
        !          7373:        if (len)
        !          7374:          len = size_binop (PLUS_EXPR, integer_one_node, len);
        !          7375:        len2 = c_strlen (arg2);
        !          7376:        if (len2)
        !          7377:          len2 = size_binop (PLUS_EXPR, integer_one_node, len2);
        !          7378: 
        !          7379:        /* If we don't have a constant length for the first, use the length
        !          7380:           of the second, if we know it.  We don't require a constant for
        !          7381:           this case; some cost analysis could be done if both are available
        !          7382:           but neither is constant.  For now, assume they're equally cheap.
        !          7383: 
        !          7384:           If both strings have constant lengths, use the smaller.  This
        !          7385:           could arise if optimization results in strcpy being called with
        !          7386:           two fixed strings, or if the code was machine-generated.  We should
        !          7387:           add some code to the `memcmp' handler below to deal with such
        !          7388:           situations, someday.  */
        !          7389:        if (!len || TREE_CODE (len) != INTEGER_CST)
        !          7390:          {
        !          7391:            if (len2)
        !          7392:              len = len2;
        !          7393:            else if (len == 0)
        !          7394:              break;
        !          7395:          }
        !          7396:        else if (len2 && TREE_CODE (len2) == INTEGER_CST)
        !          7397:          {
        !          7398:            if (tree_int_cst_lt (len2, len))
        !          7399:              len = len2;
        !          7400:          }
        !          7401: 
        !          7402:        chainon (arglist, build_tree_list (NULL_TREE, len));
        !          7403:       }
        !          7404: 
        !          7405:       /* Drops in.  */
        !          7406:     case BUILT_IN_MEMCMP:
        !          7407:       /* If not optimizing, call the library function.  */
        !          7408:       if (!optimize)
        !          7409:        break;
        !          7410: 
        !          7411:       if (arglist == 0
        !          7412:          /* Arg could be non-pointer if user redeclared this fcn wrong.  */
        !          7413:          || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
        !          7414:          || TREE_CHAIN (arglist) == 0
        !          7415:          || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != POINTER_TYPE
        !          7416:          || TREE_CHAIN (TREE_CHAIN (arglist)) == 0
        !          7417:          || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))))) != INTEGER_TYPE)
        !          7418:        break;
        !          7419:       else if (!HAVE_cmpstrsi)
        !          7420:        break;
        !          7421:       {
        !          7422:        tree arg1 = TREE_VALUE (arglist);
        !          7423:        tree arg2 = TREE_VALUE (TREE_CHAIN (arglist));
        !          7424:        tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
        !          7425:        rtx result;
        !          7426: 
        !          7427:        int arg1_align
        !          7428:          = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
        !          7429:        int arg2_align
        !          7430:          = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
        !          7431:        enum machine_mode insn_mode
        !          7432:          = insn_operand_mode[(int) CODE_FOR_cmpstrsi][0];
        !          7433: 
        !          7434:        /* If we don't have POINTER_TYPE, call the function.  */
        !          7435:        if (arg1_align == 0 || arg2_align == 0)
        !          7436:          {
        !          7437:            if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STRCMP)
        !          7438:              TREE_CHAIN (TREE_CHAIN (arglist)) = 0;
        !          7439:            break;
        !          7440:          }
        !          7441: 
        !          7442:        /* Make a place to write the result of the instruction.  */
        !          7443:        result = target;
        !          7444:        if (! (result != 0
        !          7445:               && GET_CODE (result) == REG && GET_MODE (result) == insn_mode
        !          7446:               && REGNO (result) >= FIRST_PSEUDO_REGISTER))
        !          7447:          result = gen_reg_rtx (insn_mode);
        !          7448: 
        !          7449:        emit_insn (gen_cmpstrsi (result,
        !          7450:                                 gen_rtx (MEM, BLKmode,
        !          7451:                                          expand_expr (arg1, NULL_RTX, Pmode,
        !          7452:                                                       EXPAND_NORMAL)),
        !          7453:                                 gen_rtx (MEM, BLKmode,
        !          7454:                                          expand_expr (arg2, NULL_RTX, Pmode,
        !          7455:                                                       EXPAND_NORMAL)),
        !          7456:                                 expand_expr (len, NULL_RTX, VOIDmode, 0),
        !          7457:                                 GEN_INT (MIN (arg1_align, arg2_align))));
        !          7458: 
        !          7459:        /* Return the value in the proper mode for this function.  */
        !          7460:        mode = TYPE_MODE (TREE_TYPE (exp));
        !          7461:        if (GET_MODE (result) == mode)
        !          7462:          return result;
        !          7463:        else if (target != 0)
        !          7464:          {
        !          7465:            convert_move (target, result, 0);
        !          7466:            return target;
        !          7467:          }
        !          7468:        else
        !          7469:          return convert_to_mode (mode, result, 0);
        !          7470:       }        
        !          7471: #else
        !          7472:     case BUILT_IN_STRCMP:
        !          7473:     case BUILT_IN_MEMCMP:
        !          7474:       break;
        !          7475: #endif
        !          7476: 
        !          7477:     default:                   /* just do library call, if unknown builtin */
        !          7478:       error ("built-in function `%s' not currently supported",
        !          7479:             IDENTIFIER_POINTER (DECL_NAME (fndecl)));
        !          7480:     }
        !          7481: 
        !          7482:   /* The switch statement above can drop through to cause the function
        !          7483:      to be called normally.  */
        !          7484: 
        !          7485:   return expand_call (exp, target, ignore);
        !          7486: }
        !          7487: 
        !          7488: /* Built-in functions to perform an untyped call and return.  */
        !          7489: 
        !          7490: /* For each register that may be used for calling a function, this
        !          7491:    gives a mode used to copy the register's value.  VOIDmode indicates
        !          7492:    the register is not used for calling a function.  If the machine
        !          7493:    has register windows, this gives only the outbound registers.
        !          7494:    INCOMING_REGNO gives the corresponding inbound register.  */
        !          7495: static enum machine_mode apply_args_mode[FIRST_PSEUDO_REGISTER];
        !          7496: 
        !          7497: /* For each register that may be used for returning values, this gives
        !          7498:    a mode used to copy the register's value.  VOIDmode indicates the
        !          7499:    register is not used for returning values.  If the machine has
        !          7500:    register windows, this gives only the outbound registers.
        !          7501:    INCOMING_REGNO gives the corresponding inbound register.  */
        !          7502: static enum machine_mode apply_result_mode[FIRST_PSEUDO_REGISTER];
        !          7503: 
        !          7504: /* For each register that may be used for calling a function, this
        !          7505:    gives the offset of that register into the block returned by
        !          7506:    __bultin_apply_args.  0 indicates that the register is not
        !          7507:    used for calling a function. */
        !          7508: static int apply_args_reg_offset[FIRST_PSEUDO_REGISTER];
        !          7509: 
        !          7510: /* Return the offset of register REGNO into the block returned by 
        !          7511:    __builtin_apply_args.  This is not declared static, since it is
        !          7512:    needed in objc-act.c. */
        !          7513: 
        !          7514: int 
        !          7515: apply_args_register_offset (regno)
        !          7516:      int regno;
        !          7517: {
        !          7518:   apply_args_size ();
        !          7519: 
        !          7520:   /* Arguments are always put in outgoing registers (in the argument
        !          7521:      block) if such make sense. */
        !          7522: #ifdef OUTGOING_REGNO
        !          7523:   regno = OUTGOING_REGNO(regno);
        !          7524: #endif
        !          7525:   return apply_args_reg_offset[regno];
        !          7526: }
        !          7527: 
        !          7528: /* Return the size required for the block returned by __builtin_apply_args,
        !          7529:    and initialize apply_args_mode.  */
        !          7530: 
        !          7531: static int
        !          7532: apply_args_size ()
        !          7533: {
        !          7534:   static int size = -1;
        !          7535:   int align, regno;
        !          7536:   enum machine_mode mode;
        !          7537: 
        !          7538:   /* The values computed by this function never change.  */
        !          7539:   if (size < 0)
        !          7540:     {
        !          7541:       /* The first value is the incoming arg-pointer.  */
        !          7542:       size = GET_MODE_SIZE (Pmode);
        !          7543: 
        !          7544:       /* The second value is the structure value address unless this is
        !          7545:         passed as an "invisible" first argument.  */
        !          7546:       if (struct_value_rtx)
        !          7547:        size += GET_MODE_SIZE (Pmode);
        !          7548: 
        !          7549:       for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
        !          7550:        if (FUNCTION_ARG_REGNO_P (regno))
        !          7551:          {
        !          7552:            /* Search for the proper mode for copying this register's
        !          7553:               value.  I'm not sure this is right, but it works so far.  */
        !          7554:            enum machine_mode best_mode = VOIDmode;
        !          7555: 
        !          7556:            for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
        !          7557:                 mode != VOIDmode;
        !          7558:                 mode = GET_MODE_WIDER_MODE (mode))
        !          7559:              if (HARD_REGNO_MODE_OK (regno, mode)
        !          7560:                  && HARD_REGNO_NREGS (regno, mode) == 1)
        !          7561:                best_mode = mode;
        !          7562: 
        !          7563:            if (best_mode == VOIDmode)
        !          7564:              for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
        !          7565:                   mode != VOIDmode;
        !          7566:                   mode = GET_MODE_WIDER_MODE (mode))
        !          7567:                if (HARD_REGNO_MODE_OK (regno, mode)
        !          7568:                    && (mov_optab->handlers[(int) mode].insn_code
        !          7569:                        != CODE_FOR_nothing))
        !          7570:                  best_mode = mode;
        !          7571: 
        !          7572:            mode = best_mode;
        !          7573:            if (mode == VOIDmode)
        !          7574:              abort ();
        !          7575: 
        !          7576:            align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
        !          7577:            if (size % align != 0)
        !          7578:              size = CEIL (size, align) * align;
        !          7579:            apply_args_reg_offset[regno] = size;
        !          7580:            size += GET_MODE_SIZE (mode);
        !          7581:            apply_args_mode[regno] = mode;
        !          7582:          }
        !          7583:        else
        !          7584:          {
        !          7585:            apply_args_mode[regno] = VOIDmode;
        !          7586:            apply_args_reg_offset[regno] = 0;
        !          7587:          }
        !          7588:     }
        !          7589:   return size;
        !          7590: }
        !          7591: 
        !          7592: /* Return the size required for the block returned by __builtin_apply,
        !          7593:    and initialize apply_result_mode.  */
        !          7594: 
        !          7595: static int
        !          7596: apply_result_size ()
        !          7597: {
        !          7598:   static int size = -1;
        !          7599:   int align, regno;
        !          7600:   enum machine_mode mode;
        !          7601: 
        !          7602:   /* The values computed by this function never change.  */
        !          7603:   if (size < 0)
        !          7604:     {
        !          7605:       size = 0;
        !          7606: 
        !          7607:       for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
        !          7608:        if (FUNCTION_VALUE_REGNO_P (regno))
        !          7609:          {
        !          7610:            /* Search for the proper mode for copying this register's
        !          7611:               value.  I'm not sure this is right, but it works so far.  */
        !          7612:            enum machine_mode best_mode = VOIDmode;
        !          7613: 
        !          7614:            for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
        !          7615:                 mode != TImode;
        !          7616:                 mode = GET_MODE_WIDER_MODE (mode))
        !          7617:              if (HARD_REGNO_MODE_OK (regno, mode))
        !          7618:                best_mode = mode;
        !          7619: 
        !          7620:            if (best_mode == VOIDmode)
        !          7621:              for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
        !          7622:                   mode != VOIDmode;
        !          7623:                   mode = GET_MODE_WIDER_MODE (mode))
        !          7624:                if (HARD_REGNO_MODE_OK (regno, mode)
        !          7625:                    && (mov_optab->handlers[(int) mode].insn_code
        !          7626:                        != CODE_FOR_nothing))
        !          7627:                  best_mode = mode;
        !          7628: 
        !          7629:            mode = best_mode;
        !          7630:            if (mode == VOIDmode)
        !          7631:              abort ();
        !          7632: 
        !          7633:            align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
        !          7634:            if (size % align != 0)
        !          7635:              size = CEIL (size, align) * align;
        !          7636:            size += GET_MODE_SIZE (mode);
        !          7637:            apply_result_mode[regno] = mode;
        !          7638:          }
        !          7639:        else
        !          7640:          apply_result_mode[regno] = VOIDmode;
        !          7641: 
        !          7642:       /* Allow targets that use untyped_call and untyped_return to override
        !          7643:         the size so that machine-specific information can be stored here.  */
        !          7644: #ifdef APPLY_RESULT_SIZE
        !          7645:       size = APPLY_RESULT_SIZE;
        !          7646: #endif
        !          7647:     }
        !          7648:   return size;
        !          7649: }
        !          7650: 
        !          7651: #if defined (HAVE_untyped_call) || defined (HAVE_untyped_return)
        !          7652: /* Create a vector describing the result block RESULT.  If SAVEP is true,
        !          7653:    the result block is used to save the values; otherwise it is used to
        !          7654:    restore the values.  */
        !          7655: 
        !          7656: static rtx
        !          7657: result_vector (savep, result)
        !          7658:      int savep;
        !          7659:      rtx result;
        !          7660: {
        !          7661:   int regno, size, align, nelts;
        !          7662:   enum machine_mode mode;
        !          7663:   rtx reg, mem;
        !          7664:   rtx *savevec = (rtx *) alloca (FIRST_PSEUDO_REGISTER * sizeof (rtx));
        !          7665:   
        !          7666:   size = nelts = 0;
        !          7667:   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
        !          7668:     if ((mode = apply_result_mode[regno]) != VOIDmode)
        !          7669:       {
        !          7670:        align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
        !          7671:        if (size % align != 0)
        !          7672:          size = CEIL (size, align) * align;
        !          7673:        reg = gen_rtx (REG, mode, savep ? INCOMING_REGNO (regno) : regno);
        !          7674:        mem = change_address (result, mode,
        !          7675:                              plus_constant (XEXP (result, 0), size));
        !          7676:        savevec[nelts++] = (savep
        !          7677:                            ? gen_rtx (SET, VOIDmode, mem, reg)
        !          7678:                            : gen_rtx (SET, VOIDmode, reg, mem));
        !          7679:        size += GET_MODE_SIZE (mode);
        !          7680:       }
        !          7681:   return gen_rtx (PARALLEL, VOIDmode, gen_rtvec_v (nelts, savevec));
        !          7682: }
        !          7683: #endif /* HAVE_untyped_call or HAVE_untyped_return */
        !          7684: 
        !          7685: /* Save the state required to perform an untyped call with the same
        !          7686:    arguments as were passed to the current function.  */
        !          7687: 
        !          7688: static rtx
        !          7689: expand_builtin_apply_args ()
        !          7690: {
        !          7691:   rtx registers;
        !          7692:   int size, align, regno;
        !          7693:   enum machine_mode mode;
        !          7694: 
        !          7695:   /* Create a block where the arg-pointer, structure value address,
        !          7696:      and argument registers can be saved.  */
        !          7697:   registers = assign_stack_local (BLKmode, apply_args_size (), -1);
        !          7698: 
        !          7699:   /* Walk past the arg-pointer and structure value address.  */
        !          7700:   size = GET_MODE_SIZE (Pmode);
        !          7701:   if (struct_value_rtx)
        !          7702:     size += GET_MODE_SIZE (Pmode);
        !          7703: 
        !          7704:   /* Save each register used in calling a function to the block.  */
        !          7705:   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
        !          7706:     if ((mode = apply_args_mode[regno]) != VOIDmode)
        !          7707:       {
        !          7708:        align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
        !          7709:        if (size % align != 0)
        !          7710:          size = CEIL (size, align) * align;
        !          7711:        emit_move_insn (change_address (registers, mode,
        !          7712:                                        plus_constant (XEXP (registers, 0),
        !          7713:                                                       size)),
        !          7714:                        gen_rtx (REG, mode, INCOMING_REGNO (regno)));
        !          7715:        size += GET_MODE_SIZE (mode);
        !          7716:       }
        !          7717: 
        !          7718:   /* Save the arg pointer to the block.  */
        !          7719:   emit_move_insn (change_address (registers, Pmode, XEXP (registers, 0)),
        !          7720:                  copy_to_reg (virtual_incoming_args_rtx));
        !          7721:   size = GET_MODE_SIZE (Pmode);
        !          7722: 
        !          7723:   /* Save the structure value address unless this is passed as an
        !          7724:      "invisible" first argument.  */
        !          7725:   if (struct_value_incoming_rtx)
        !          7726:     {
        !          7727:       emit_move_insn (change_address (registers, Pmode,
        !          7728:                                      plus_constant (XEXP (registers, 0),
        !          7729:                                                     size)),
        !          7730:                      copy_to_reg (struct_value_incoming_rtx));
        !          7731:       size += GET_MODE_SIZE (Pmode);
        !          7732:     }
        !          7733: 
        !          7734:   /* Return the address of the block.  */
        !          7735:   return copy_addr_to_reg (XEXP (registers, 0));
        !          7736: }
        !          7737: 
        !          7738: /* Perform an untyped call and save the state required to perform an
        !          7739:    untyped return of whatever value was returned by the given function.  */
        !          7740: 
        !          7741: static rtx
        !          7742: expand_builtin_apply (function, arguments, argsize)
        !          7743:      rtx function, arguments, argsize;
        !          7744: {
        !          7745:   int size, align, regno;
        !          7746:   enum machine_mode mode;
        !          7747:   rtx incoming_args, result, reg, dest, call_insn;
        !          7748:   rtx old_stack_level = 0;
        !          7749:   rtx use_insns = 0;
        !          7750: 
        !          7751:   /* Create a block where the return registers can be saved.  */
        !          7752:   result = assign_stack_local (BLKmode, apply_result_size (), -1);
        !          7753: 
        !          7754:   /* ??? The argsize value should be adjusted here.  */
        !          7755: 
        !          7756:   /* Fetch the arg pointer from the ARGUMENTS block.  */
        !          7757:   incoming_args = gen_reg_rtx (Pmode);
        !          7758:   emit_move_insn (incoming_args,
        !          7759:                  gen_rtx (MEM, Pmode, arguments));
        !          7760: #ifndef STACK_GROWS_DOWNWARD
        !          7761:   incoming_args = expand_binop (Pmode, sub_optab, incoming_args, argsize,
        !          7762:                                incoming_args, 0, OPTAB_LIB_WIDEN);
        !          7763: #endif
        !          7764: 
        !          7765:   /* Perform postincrements before actually calling the function.  */
        !          7766:   emit_queue ();
        !          7767: 
        !          7768:   /* Push a new argument block and copy the arguments.  */
        !          7769:   do_pending_stack_adjust ();
        !          7770:   emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX);
        !          7771: 
        !          7772:   /* Push a block of memory onto the stack to store the memory arguments.
        !          7773:      Save the address in a register, and copy the memory arguments.  ??? I
        !          7774:      haven't figured out how the calling convention macros effect this,
        !          7775:      but it's likely that the source and/or destination addresses in
        !          7776:      the block copy will need updating in machine specific ways.  */
        !          7777:   dest = copy_addr_to_reg (push_block (argsize, 0, 0));
        !          7778:   emit_block_move (gen_rtx (MEM, BLKmode, dest),
        !          7779:                   gen_rtx (MEM, BLKmode, incoming_args),
        !          7780:                   argsize,
        !          7781:                   PARM_BOUNDARY / BITS_PER_UNIT);
        !          7782: 
        !          7783:   /* Refer to the argument block.  */
        !          7784:   apply_args_size ();
        !          7785:   arguments = gen_rtx (MEM, BLKmode, arguments);
        !          7786: 
        !          7787:   /* Walk past the arg-pointer and structure value address.  */
        !          7788:   size = GET_MODE_SIZE (Pmode);
        !          7789:   if (struct_value_rtx)
        !          7790:     size += GET_MODE_SIZE (Pmode);
        !          7791: 
        !          7792:   /* Restore each of the registers previously saved.  Make USE insns
        !          7793:      for each of these registers for use in making the call.  */
        !          7794:   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
        !          7795:     if ((mode = apply_args_mode[regno]) != VOIDmode)
        !          7796:       {
        !          7797:        align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
        !          7798:        if (size % align != 0)
        !          7799:          size = CEIL (size, align) * align;
        !          7800:        reg = gen_rtx (REG, mode, regno);
        !          7801:        emit_move_insn (reg,
        !          7802:                        change_address (arguments, mode,
        !          7803:                                        plus_constant (XEXP (arguments, 0),
        !          7804:                                                       size)));
        !          7805: 
        !          7806:        push_to_sequence (use_insns);
        !          7807:        emit_insn (gen_rtx (USE, VOIDmode, reg));
        !          7808:        use_insns = get_insns ();
        !          7809:        end_sequence ();
        !          7810:        size += GET_MODE_SIZE (mode);
        !          7811:       }
        !          7812: 
        !          7813:   /* Restore the structure value address unless this is passed as an
        !          7814:      "invisible" first argument.  */
        !          7815:   size = GET_MODE_SIZE (Pmode);
        !          7816:   if (struct_value_rtx)
        !          7817:     {
        !          7818:       rtx value = gen_reg_rtx (Pmode);
        !          7819:       emit_move_insn (value,
        !          7820:                      change_address (arguments, Pmode,
        !          7821:                                      plus_constant (XEXP (arguments, 0),
        !          7822:                                                     size)));
        !          7823:       emit_move_insn (struct_value_rtx, value);
        !          7824:       if (GET_CODE (struct_value_rtx) == REG)
        !          7825:        {
        !          7826:          push_to_sequence (use_insns);
        !          7827:          emit_insn (gen_rtx (USE, VOIDmode, struct_value_rtx));
        !          7828:          use_insns = get_insns ();
        !          7829:          end_sequence ();
        !          7830:        }
        !          7831:       size += GET_MODE_SIZE (Pmode);
        !          7832:     }
        !          7833: 
        !          7834:   /* All arguments and registers used for the call are set up by now!  */
        !          7835:   function = prepare_call_address (function, NULL_TREE, &use_insns);
        !          7836: 
        !          7837:   /* Ensure address is valid.  SYMBOL_REF is already valid, so no need,
        !          7838:      and we don't want to load it into a register as an optimization,
        !          7839:      because prepare_call_address already did it if it should be done.  */
        !          7840:   if (GET_CODE (function) != SYMBOL_REF)
        !          7841:     function = memory_address (FUNCTION_MODE, function);
        !          7842: 
        !          7843:   /* Generate the actual call instruction and save the return value.  */
        !          7844: #ifdef HAVE_untyped_call
        !          7845:   if (HAVE_untyped_call)
        !          7846:     emit_call_insn (gen_untyped_call (gen_rtx (MEM, FUNCTION_MODE, function),
        !          7847:                                      result, result_vector (1, result)));
        !          7848:   else
        !          7849: #endif
        !          7850: #ifdef HAVE_call_value
        !          7851:   if (HAVE_call_value)
        !          7852:     {
        !          7853:       rtx valreg = 0;
        !          7854: 
        !          7855:       /* Locate the unique return register.  It is not possible to
        !          7856:         express a call that sets more than one return register using
        !          7857:         call_value; use untyped_call for that.  In fact, untyped_call
        !          7858:         only needs to save the return registers in the given block.  */
        !          7859:       for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
        !          7860:        if ((mode = apply_result_mode[regno]) != VOIDmode)
        !          7861:          {
        !          7862:            if (valreg)
        !          7863:              abort (); /* HAVE_untyped_call required.  */
        !          7864:            valreg = gen_rtx (REG, mode, regno);
        !          7865:          }
        !          7866: 
        !          7867:       emit_call_insn (gen_call_value (valreg,
        !          7868:                                      gen_rtx (MEM, FUNCTION_MODE, function),
        !          7869:                                      const0_rtx, NULL_RTX, const0_rtx));
        !          7870: 
        !          7871:       emit_move_insn (change_address (result, GET_MODE (valreg),
        !          7872:                                      XEXP (result, 0)),
        !          7873:                      valreg);
        !          7874:     }
        !          7875:   else
        !          7876: #endif
        !          7877:     abort ();
        !          7878: 
        !          7879:   /* Find the CALL insn we just emitted and write the USE insns before it.  */
        !          7880:   for (call_insn = get_last_insn ();
        !          7881:        call_insn && GET_CODE (call_insn) != CALL_INSN;
        !          7882:        call_insn = PREV_INSN (call_insn))
        !          7883:     ;
        !          7884: 
        !          7885:   if (! call_insn)
        !          7886:     abort ();
        !          7887: 
        !          7888:   /* Put the USE insns before the CALL.  */
        !          7889:   emit_insns_before (use_insns, call_insn);
        !          7890: 
        !          7891:   /* Restore the stack.  */
        !          7892:   emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX);
        !          7893: 
        !          7894:   /* Return the address of the result block.  */
        !          7895:   return copy_addr_to_reg (XEXP (result, 0));
        !          7896: }
        !          7897: 
        !          7898: /* Perform an untyped return.  */
        !          7899: 
        !          7900: static void
        !          7901: expand_builtin_return (result)
        !          7902:      rtx result;
        !          7903: {
        !          7904:   int size, align, regno;
        !          7905:   enum machine_mode mode;
        !          7906:   rtx reg;
        !          7907:   rtx use_insns = 0;
        !          7908: 
        !          7909:   apply_result_size ();
        !          7910:   result = gen_rtx (MEM, BLKmode, result);
        !          7911: 
        !          7912: #ifdef HAVE_untyped_return
        !          7913:   if (HAVE_untyped_return)
        !          7914:     {
        !          7915:       emit_jump_insn (gen_untyped_return (result, result_vector (0, result)));
        !          7916:       emit_barrier ();
        !          7917:       return;
        !          7918:     }
        !          7919: #endif
        !          7920: 
        !          7921:   /* Restore the return value and note that each value is used.  */
        !          7922:   size = 0;
        !          7923:   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
        !          7924:     if ((mode = apply_result_mode[regno]) != VOIDmode)
        !          7925:       {
        !          7926:        align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
        !          7927:        if (size % align != 0)
        !          7928:          size = CEIL (size, align) * align;
        !          7929:        reg = gen_rtx (REG, mode, INCOMING_REGNO (regno));
        !          7930:        emit_move_insn (reg,
        !          7931:                        change_address (result, mode,
        !          7932:                                        plus_constant (XEXP (result, 0),
        !          7933:                                                       size)));
        !          7934: 
        !          7935:        push_to_sequence (use_insns);
        !          7936:        emit_insn (gen_rtx (USE, VOIDmode, reg));
        !          7937:        use_insns = get_insns ();
        !          7938:        end_sequence ();
        !          7939:        size += GET_MODE_SIZE (mode);
        !          7940:       }
        !          7941: 
        !          7942:   /* Put the USE insns before the return.  */
        !          7943:   emit_insns (use_insns);
        !          7944: 
        !          7945:   /* Return whatever values was restored by jumping directly to the end
        !          7946:      of the function.  */
        !          7947:   expand_null_return ();
        !          7948: }
        !          7949: 
        !          7950: /* Expand code for a post- or pre- increment or decrement
        !          7951:    and return the RTX for the result.
        !          7952:    POST is 1 for postinc/decrements and 0 for preinc/decrements.  */
        !          7953: 
        !          7954: static rtx
        !          7955: expand_increment (exp, post)
        !          7956:      register tree exp;
        !          7957:      int post;
        !          7958: {
        !          7959:   register rtx op0, op1;
        !          7960:   register rtx temp, value;
        !          7961:   register tree incremented = TREE_OPERAND (exp, 0);
        !          7962:   optab this_optab = add_optab;
        !          7963:   int icode;
        !          7964:   enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
        !          7965:   int op0_is_copy = 0;
        !          7966:   int single_insn = 0;
        !          7967:   /* 1 means we can't store into OP0 directly,
        !          7968:      because it is a subreg narrower than a word,
        !          7969:      and we don't dare clobber the rest of the word.  */
        !          7970:   int bad_subreg = 0;
        !          7971: 
        !          7972:   if (output_bytecode)
        !          7973:     {
        !          7974:       bc_expand_expr (exp);
        !          7975:       return NULL_RTX;
        !          7976:     }
        !          7977: 
        !          7978:   /* Stabilize any component ref that might need to be
        !          7979:      evaluated more than once below.  */
        !          7980:   if (!post
        !          7981:       || TREE_CODE (incremented) == BIT_FIELD_REF
        !          7982:       || (TREE_CODE (incremented) == COMPONENT_REF
        !          7983:          && (TREE_CODE (TREE_OPERAND (incremented, 0)) != INDIRECT_REF
        !          7984:              || DECL_BIT_FIELD (TREE_OPERAND (incremented, 1)))))
        !          7985:     incremented = stabilize_reference (incremented);
        !          7986:   /* Nested *INCREMENT_EXPRs can happen in C++.  We must force innermost
        !          7987:      ones into save exprs so that they don't accidentally get evaluated
        !          7988:      more than once by the code below.  */
        !          7989:   if (TREE_CODE (incremented) == PREINCREMENT_EXPR
        !          7990:       || TREE_CODE (incremented) == PREDECREMENT_EXPR)
        !          7991:     incremented = save_expr (incremented);
        !          7992: 
        !          7993:   /* Compute the operands as RTX.
        !          7994:      Note whether OP0 is the actual lvalue or a copy of it:
        !          7995:      I believe it is a copy iff it is a register or subreg
        !          7996:      and insns were generated in computing it.   */
        !          7997: 
        !          7998:   temp = get_last_insn ();
        !          7999:   op0 = expand_expr (incremented, NULL_RTX, VOIDmode, 0);
        !          8000: 
        !          8001:   /* If OP0 is a SUBREG made for a promoted variable, we cannot increment
        !          8002:      in place but intead must do sign- or zero-extension during assignment,
        !          8003:      so we copy it into a new register and let the code below use it as
        !          8004:      a copy.
        !          8005: 
        !          8006:      Note that we can safely modify this SUBREG since it is know not to be
        !          8007:      shared (it was made by the expand_expr call above).  */
        !          8008: 
        !          8009:   if (GET_CODE (op0) == SUBREG && SUBREG_PROMOTED_VAR_P (op0))
        !          8010:     SUBREG_REG (op0) = copy_to_reg (SUBREG_REG (op0));
        !          8011:   else if (GET_CODE (op0) == SUBREG
        !          8012:           && GET_MODE_BITSIZE (GET_MODE (op0)) < BITS_PER_WORD)
        !          8013:     bad_subreg = 1;
        !          8014: 
        !          8015:   op0_is_copy = ((GET_CODE (op0) == SUBREG || GET_CODE (op0) == REG)
        !          8016:                 && temp != get_last_insn ());
        !          8017:   op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
        !          8018: 
        !          8019:   /* Decide whether incrementing or decrementing.  */
        !          8020:   if (TREE_CODE (exp) == POSTDECREMENT_EXPR
        !          8021:       || TREE_CODE (exp) == PREDECREMENT_EXPR)
        !          8022:     this_optab = sub_optab;
        !          8023: 
        !          8024:   /* Convert decrement by a constant into a negative increment.  */
        !          8025:   if (this_optab == sub_optab
        !          8026:       && GET_CODE (op1) == CONST_INT)
        !          8027:     {
        !          8028:       op1 = GEN_INT (- INTVAL (op1));
        !          8029:       this_optab = add_optab;
        !          8030:     }
        !          8031: 
        !          8032:   /* For a preincrement, see if we can do this with a single instruction.  */
        !          8033:   if (!post)
        !          8034:     {
        !          8035:       icode = (int) this_optab->handlers[(int) mode].insn_code;
        !          8036:       if (icode != (int) CODE_FOR_nothing
        !          8037:          /* Make sure that OP0 is valid for operands 0 and 1
        !          8038:             of the insn we want to queue.  */
        !          8039:          && (*insn_operand_predicate[icode][0]) (op0, mode)
        !          8040:          && (*insn_operand_predicate[icode][1]) (op0, mode)
        !          8041:          && (*insn_operand_predicate[icode][2]) (op1, mode))
        !          8042:        single_insn = 1;
        !          8043:     }
        !          8044: 
        !          8045:   /* If OP0 is not the actual lvalue, but rather a copy in a register,
        !          8046:      then we cannot just increment OP0.  We must therefore contrive to
        !          8047:      increment the original value.  Then, for postincrement, we can return
        !          8048:      OP0 since it is a copy of the old value.  For preincrement, expand here
        !          8049:      unless we can do it with a single insn.
        !          8050: 
        !          8051:      Likewise if storing directly into OP0 would clobber high bits
        !          8052:      we need to preserve (bad_subreg).  */
        !          8053:   if (op0_is_copy || (!post && !single_insn) || bad_subreg)
        !          8054:     {
        !          8055:       /* This is the easiest way to increment the value wherever it is.
        !          8056:         Problems with multiple evaluation of INCREMENTED are prevented
        !          8057:         because either (1) it is a component_ref or preincrement,
        !          8058:         in which case it was stabilized above, or (2) it is an array_ref
        !          8059:         with constant index in an array in a register, which is
        !          8060:         safe to reevaluate.  */
        !          8061:       tree newexp = build (((TREE_CODE (exp) == POSTDECREMENT_EXPR
        !          8062:                             || TREE_CODE (exp) == PREDECREMENT_EXPR)
        !          8063:                            ? MINUS_EXPR : PLUS_EXPR),
        !          8064:                           TREE_TYPE (exp),
        !          8065:                           incremented,
        !          8066:                           TREE_OPERAND (exp, 1));
        !          8067:       temp = expand_assignment (incremented, newexp, ! post, 0);
        !          8068:       return post ? op0 : temp;
        !          8069:     }
        !          8070: 
        !          8071:   if (post)
        !          8072:     {
        !          8073:       /* We have a true reference to the value in OP0.
        !          8074:         If there is an insn to add or subtract in this mode, queue it.
        !          8075:         Queueing the increment insn avoids the register shuffling
        !          8076:         that often results if we must increment now and first save
        !          8077:         the old value for subsequent use.  */
        !          8078: 
        !          8079: #if 0  /* Turned off to avoid making extra insn for indexed memref.  */
        !          8080:       op0 = stabilize (op0);
        !          8081: #endif
        !          8082: 
        !          8083:       icode = (int) this_optab->handlers[(int) mode].insn_code;
        !          8084:       if (icode != (int) CODE_FOR_nothing
        !          8085:          /* Make sure that OP0 is valid for operands 0 and 1
        !          8086:             of the insn we want to queue.  */
        !          8087:          && (*insn_operand_predicate[icode][0]) (op0, mode)
        !          8088:          && (*insn_operand_predicate[icode][1]) (op0, mode))
        !          8089:        {
        !          8090:          if (! (*insn_operand_predicate[icode][2]) (op1, mode))
        !          8091:            op1 = force_reg (mode, op1);
        !          8092: 
        !          8093:          return enqueue_insn (op0, GEN_FCN (icode) (op0, op0, op1));
        !          8094:        }
        !          8095:     }
        !          8096: 
        !          8097:   /* Preincrement, or we can't increment with one simple insn.  */
        !          8098:   if (post)
        !          8099:     /* Save a copy of the value before inc or dec, to return it later.  */
        !          8100:     temp = value = copy_to_reg (op0);
        !          8101:   else
        !          8102:     /* Arrange to return the incremented value.  */
        !          8103:     /* Copy the rtx because expand_binop will protect from the queue,
        !          8104:        and the results of that would be invalid for us to return
        !          8105:        if our caller does emit_queue before using our result.  */
        !          8106:     temp = copy_rtx (value = op0);
        !          8107: 
        !          8108:   /* Increment however we can.  */
        !          8109:   op1 = expand_binop (mode, this_optab, value, op1, op0,
        !          8110:                      TREE_UNSIGNED (TREE_TYPE (exp)), OPTAB_LIB_WIDEN);
        !          8111:   /* Make sure the value is stored into OP0.  */
        !          8112:   if (op1 != op0)
        !          8113:     emit_move_insn (op0, op1);
        !          8114: 
        !          8115:   return temp;
        !          8116: }
        !          8117: 
        !          8118: /* Expand all function calls contained within EXP, innermost ones first.
        !          8119:    But don't look within expressions that have sequence points.
        !          8120:    For each CALL_EXPR, record the rtx for its value
        !          8121:    in the CALL_EXPR_RTL field.  */
        !          8122: 
        !          8123: static void
        !          8124: preexpand_calls (exp)
        !          8125:      tree exp;
        !          8126: {
        !          8127:   register int nops, i;
        !          8128:   int type = TREE_CODE_CLASS (TREE_CODE (exp));
        !          8129: 
        !          8130:   if (! do_preexpand_calls)
        !          8131:     return;
        !          8132: 
        !          8133:   /* Only expressions and references can contain calls.  */
        !          8134: 
        !          8135:   if (type != 'e' && type != '<' && type != '1' && type != '2' && type != 'r')
        !          8136:     return;
        !          8137: 
        !          8138:   switch (TREE_CODE (exp))
        !          8139:     {
        !          8140:     case CALL_EXPR:
        !          8141:       /* Do nothing if already expanded.  */
        !          8142:       if (CALL_EXPR_RTL (exp) != 0)
        !          8143:        return;
        !          8144: 
        !          8145:       /* Do nothing to built-in functions.  */
        !          8146:       if (TREE_CODE (TREE_OPERAND (exp, 0)) != ADDR_EXPR
        !          8147:          || TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) != FUNCTION_DECL
        !          8148:          || ! DECL_BUILT_IN (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
        !          8149:        CALL_EXPR_RTL (exp) = expand_call (exp, NULL_RTX, 0);
        !          8150:       return;
        !          8151: 
        !          8152:     case COMPOUND_EXPR:
        !          8153:     case COND_EXPR:
        !          8154:     case TRUTH_ANDIF_EXPR:
        !          8155:     case TRUTH_ORIF_EXPR:
        !          8156:       /* If we find one of these, then we can be sure
        !          8157:         the adjust will be done for it (since it makes jumps).
        !          8158:         Do it now, so that if this is inside an argument
        !          8159:         of a function, we don't get the stack adjustment
        !          8160:         after some other args have already been pushed.  */
        !          8161:       do_pending_stack_adjust ();
        !          8162:       return;
        !          8163: 
        !          8164:     case BLOCK:
        !          8165:     case RTL_EXPR:
        !          8166:     case WITH_CLEANUP_EXPR:
        !          8167:       return;
        !          8168: 
        !          8169:     case SAVE_EXPR:
        !          8170:       if (SAVE_EXPR_RTL (exp) != 0)
        !          8171:        return;
        !          8172:     }
        !          8173: 
        !          8174:   nops = tree_code_length[(int) TREE_CODE (exp)];
        !          8175:   for (i = 0; i < nops; i++)
        !          8176:     if (TREE_OPERAND (exp, i) != 0)
        !          8177:       {
        !          8178:        type = TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, i)));
        !          8179:        if (type == 'e' || type == '<' || type == '1' || type == '2'
        !          8180:            || type == 'r')
        !          8181:          preexpand_calls (TREE_OPERAND (exp, i));
        !          8182:       }
        !          8183: }
        !          8184: 
        !          8185: /* At the start of a function, record that we have no previously-pushed
        !          8186:    arguments waiting to be popped.  */
        !          8187: 
        !          8188: void
        !          8189: init_pending_stack_adjust ()
        !          8190: {
        !          8191:   pending_stack_adjust = 0;
        !          8192: }
        !          8193: 
        !          8194: /* When exiting from function, if safe, clear out any pending stack adjust
        !          8195:    so the adjustment won't get done.  */
        !          8196: 
        !          8197: void
        !          8198: clear_pending_stack_adjust ()
        !          8199: {
        !          8200: #ifdef EXIT_IGNORE_STACK
        !          8201:   if (! flag_omit_frame_pointer && EXIT_IGNORE_STACK
        !          8202:       && ! (DECL_INLINE (current_function_decl) && ! flag_no_inline)
        !          8203:       && ! flag_inline_functions)
        !          8204:     pending_stack_adjust = 0;
        !          8205: #endif
        !          8206: }
        !          8207: 
        !          8208: /* Pop any previously-pushed arguments that have not been popped yet.  */
        !          8209: 
        !          8210: void
        !          8211: do_pending_stack_adjust ()
        !          8212: {
        !          8213:   if (inhibit_defer_pop == 0)
        !          8214:     {
        !          8215:       if (pending_stack_adjust != 0)
        !          8216:        adjust_stack (GEN_INT (pending_stack_adjust));
        !          8217:       pending_stack_adjust = 0;
        !          8218:     }
        !          8219: }
        !          8220: 
        !          8221: /* Expand all cleanups up to OLD_CLEANUPS.
        !          8222:    Needed here, and also for language-dependent calls.  */
        !          8223: 
        !          8224: void
        !          8225: expand_cleanups_to (old_cleanups)
        !          8226:      tree old_cleanups;
        !          8227: {
        !          8228:   while (cleanups_this_call != old_cleanups)
        !          8229:     {
        !          8230:       expand_expr (TREE_VALUE (cleanups_this_call), NULL_RTX, VOIDmode, 0);
        !          8231:       cleanups_this_call = TREE_CHAIN (cleanups_this_call);
        !          8232:     }
        !          8233: }
        !          8234: 
        !          8235: /* Expand conditional expressions.  */
        !          8236: 
        !          8237: /* Generate code to evaluate EXP and jump to LABEL if the value is zero.
        !          8238:    LABEL is an rtx of code CODE_LABEL, in this function and all the
        !          8239:    functions here.  */
        !          8240: 
        !          8241: void
        !          8242: jumpifnot (exp, label)
        !          8243:      tree exp;
        !          8244:      rtx label;
        !          8245: {
        !          8246:   do_jump (exp, label, NULL_RTX);
        !          8247: }
        !          8248: 
        !          8249: /* Generate code to evaluate EXP and jump to LABEL if the value is nonzero.  */
        !          8250: 
        !          8251: void
        !          8252: jumpif (exp, label)
        !          8253:      tree exp;
        !          8254:      rtx label;
        !          8255: {
        !          8256:   do_jump (exp, NULL_RTX, label);
        !          8257: }
        !          8258: 
        !          8259: /* Generate code to evaluate EXP and jump to IF_FALSE_LABEL if
        !          8260:    the result is zero, or IF_TRUE_LABEL if the result is one.
        !          8261:    Either of IF_FALSE_LABEL and IF_TRUE_LABEL may be zero,
        !          8262:    meaning fall through in that case.
        !          8263: 
        !          8264:    do_jump always does any pending stack adjust except when it does not
        !          8265:    actually perform a jump.  An example where there is no jump
        !          8266:    is when EXP is `(foo (), 0)' and IF_FALSE_LABEL is null.
        !          8267: 
        !          8268:    This function is responsible for optimizing cases such as
        !          8269:    &&, || and comparison operators in EXP.  */
        !          8270: 
        !          8271: void
        !          8272: do_jump (exp, if_false_label, if_true_label)
        !          8273:      tree exp;
        !          8274:      rtx if_false_label, if_true_label;
        !          8275: {
        !          8276:   register enum tree_code code = TREE_CODE (exp);
        !          8277:   /* Some cases need to create a label to jump to
        !          8278:      in order to properly fall through.
        !          8279:      These cases set DROP_THROUGH_LABEL nonzero.  */
        !          8280:   rtx drop_through_label = 0;
        !          8281:   rtx temp;
        !          8282:   rtx comparison = 0;
        !          8283:   int i;
        !          8284:   tree type;
        !          8285: 
        !          8286:   emit_queue ();
        !          8287: 
        !          8288:   switch (code)
        !          8289:     {
        !          8290:     case ERROR_MARK:
        !          8291:       break;
        !          8292: 
        !          8293:     case INTEGER_CST:
        !          8294:       temp = integer_zerop (exp) ? if_false_label : if_true_label;
        !          8295:       if (temp)
        !          8296:        emit_jump (temp);
        !          8297:       break;
        !          8298: 
        !          8299: #if 0
        !          8300:       /* This is not true with #pragma weak  */
        !          8301:     case ADDR_EXPR:
        !          8302:       /* The address of something can never be zero.  */
        !          8303:       if (if_true_label)
        !          8304:        emit_jump (if_true_label);
        !          8305:       break;
        !          8306: #endif
        !          8307: 
        !          8308:     case NOP_EXPR:
        !          8309:       if (TREE_CODE (TREE_OPERAND (exp, 0)) == COMPONENT_REF
        !          8310:          || TREE_CODE (TREE_OPERAND (exp, 0)) == BIT_FIELD_REF
        !          8311:          || TREE_CODE (TREE_OPERAND (exp, 0)) == ARRAY_REF)
        !          8312:        goto normal;
        !          8313:     case CONVERT_EXPR:
        !          8314:       /* If we are narrowing the operand, we have to do the compare in the
        !          8315:         narrower mode.  */
        !          8316:       if ((TYPE_PRECISION (TREE_TYPE (exp))
        !          8317:           < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0)))))
        !          8318:        goto normal;
        !          8319:     case NON_LVALUE_EXPR:
        !          8320:     case REFERENCE_EXPR:
        !          8321:     case ABS_EXPR:
        !          8322:     case NEGATE_EXPR:
        !          8323:     case LROTATE_EXPR:
        !          8324:     case RROTATE_EXPR:
        !          8325:       /* These cannot change zero->non-zero or vice versa.  */
        !          8326:       do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
        !          8327:       break;
        !          8328: 
        !          8329: #if 0
        !          8330:       /* This is never less insns than evaluating the PLUS_EXPR followed by
        !          8331:         a test and can be longer if the test is eliminated.  */
        !          8332:     case PLUS_EXPR:
        !          8333:       /* Reduce to minus.  */
        !          8334:       exp = build (MINUS_EXPR, TREE_TYPE (exp),
        !          8335:                   TREE_OPERAND (exp, 0),
        !          8336:                   fold (build1 (NEGATE_EXPR, TREE_TYPE (TREE_OPERAND (exp, 1)),
        !          8337:                                 TREE_OPERAND (exp, 1))));
        !          8338:       /* Process as MINUS.  */
        !          8339: #endif
        !          8340: 
        !          8341:     case MINUS_EXPR:
        !          8342:       /* Non-zero iff operands of minus differ.  */
        !          8343:       comparison = compare (build (NE_EXPR, TREE_TYPE (exp),
        !          8344:                                   TREE_OPERAND (exp, 0),
        !          8345:                                   TREE_OPERAND (exp, 1)),
        !          8346:                            NE, NE);
        !          8347:       break;
        !          8348: 
        !          8349:     case BIT_AND_EXPR:
        !          8350:       /* If we are AND'ing with a small constant, do this comparison in the
        !          8351:         smallest type that fits.  If the machine doesn't have comparisons
        !          8352:         that small, it will be converted back to the wider comparison.
        !          8353:         This helps if we are testing the sign bit of a narrower object.
        !          8354:         combine can't do this for us because it can't know whether a
        !          8355:         ZERO_EXTRACT or a compare in a smaller mode exists, but we do.  */
        !          8356: 
        !          8357:       if (! SLOW_BYTE_ACCESS
        !          8358:          && TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
        !          8359:          && TYPE_PRECISION (TREE_TYPE (exp)) <= HOST_BITS_PER_WIDE_INT
        !          8360:          && (i = floor_log2 (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)))) >= 0
        !          8361:          && (type = type_for_size (i + 1, 1)) != 0
        !          8362:          && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (exp))
        !          8363:          && (cmp_optab->handlers[(int) TYPE_MODE (type)].insn_code
        !          8364:              != CODE_FOR_nothing))
        !          8365:        {
        !          8366:          do_jump (convert (type, exp), if_false_label, if_true_label);
        !          8367:          break;
        !          8368:        }
        !          8369:       goto normal;
        !          8370: 
        !          8371:     case TRUTH_NOT_EXPR:
        !          8372:       do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label);
        !          8373:       break;
        !          8374: 
        !          8375:     case TRUTH_ANDIF_EXPR:
        !          8376:       if (if_false_label == 0)
        !          8377:        if_false_label = drop_through_label = gen_label_rtx ();
        !          8378:       do_jump (TREE_OPERAND (exp, 0), if_false_label, NULL_RTX);
        !          8379:       do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
        !          8380:       break;
        !          8381: 
        !          8382:     case TRUTH_ORIF_EXPR:
        !          8383:       if (if_true_label == 0)
        !          8384:        if_true_label = drop_through_label = gen_label_rtx ();
        !          8385:       do_jump (TREE_OPERAND (exp, 0), NULL_RTX, if_true_label);
        !          8386:       do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
        !          8387:       break;
        !          8388: 
        !          8389:     case COMPOUND_EXPR:
        !          8390:       push_temp_slots ();
        !          8391:       expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0);
        !          8392:       free_temp_slots ();
        !          8393:       pop_temp_slots ();
        !          8394:       emit_queue ();
        !          8395:       do_pending_stack_adjust ();
        !          8396:       do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
        !          8397:       break;
        !          8398: 
        !          8399:     case COMPONENT_REF:
        !          8400:     case BIT_FIELD_REF:
        !          8401:     case ARRAY_REF:
        !          8402:       {
        !          8403:        int bitsize, bitpos, unsignedp;
        !          8404:        enum machine_mode mode;
        !          8405:        tree type;
        !          8406:        tree offset;
        !          8407:        int volatilep = 0;
        !          8408: 
        !          8409:        /* Get description of this reference.  We don't actually care
        !          8410:           about the underlying object here.  */
        !          8411:        get_inner_reference (exp, &bitsize, &bitpos, &offset,
        !          8412:                             &mode, &unsignedp, &volatilep);
        !          8413: 
        !          8414:        type = type_for_size (bitsize, unsignedp);
        !          8415:        if (! SLOW_BYTE_ACCESS
        !          8416:            && type != 0 && bitsize >= 0
        !          8417:            && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (exp))
        !          8418:            && (cmp_optab->handlers[(int) TYPE_MODE (type)].insn_code
        !          8419:                != CODE_FOR_nothing))
        !          8420:          {
        !          8421:            do_jump (convert (type, exp), if_false_label, if_true_label);
        !          8422:            break;
        !          8423:          }
        !          8424:        goto normal;
        !          8425:       }
        !          8426: 
        !          8427:     case COND_EXPR:
        !          8428:       /* Do (a ? 1 : 0) and (a ? 0 : 1) as special cases.  */
        !          8429:       if (integer_onep (TREE_OPERAND (exp, 1))
        !          8430:          && integer_zerop (TREE_OPERAND (exp, 2)))
        !          8431:        do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
        !          8432: 
        !          8433:       else if (integer_zerop (TREE_OPERAND (exp, 1))
        !          8434:               && integer_onep (TREE_OPERAND (exp, 2)))
        !          8435:        do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label);
        !          8436: 
        !          8437:       else
        !          8438:        {
        !          8439:          register rtx label1 = gen_label_rtx ();
        !          8440:          drop_through_label = gen_label_rtx ();
        !          8441:          do_jump (TREE_OPERAND (exp, 0), label1, NULL_RTX);
        !          8442:          /* Now the THEN-expression.  */
        !          8443:          do_jump (TREE_OPERAND (exp, 1),
        !          8444:                   if_false_label ? if_false_label : drop_through_label,
        !          8445:                   if_true_label ? if_true_label : drop_through_label);
        !          8446:          /* In case the do_jump just above never jumps.  */
        !          8447:          do_pending_stack_adjust ();
        !          8448:          emit_label (label1);
        !          8449:          /* Now the ELSE-expression.  */
        !          8450:          do_jump (TREE_OPERAND (exp, 2),
        !          8451:                   if_false_label ? if_false_label : drop_through_label,
        !          8452:                   if_true_label ? if_true_label : drop_through_label);
        !          8453:        }
        !          8454:       break;
        !          8455: 
        !          8456:     case EQ_EXPR:
        !          8457:       if (integer_zerop (TREE_OPERAND (exp, 1)))
        !          8458:        do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label);
        !          8459:       else if (((GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
        !          8460:                 == MODE_INT)
        !          8461:                && 
        !          8462:                !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
        !          8463:               || GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))) == MODE_COMPLEX_FLOAT
        !          8464:               || GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))) == MODE_COMPLEX_INT)
        !          8465:        do_jump_by_parts_equality (exp, if_false_label, if_true_label);
        !          8466:       else
        !          8467:        comparison = compare (exp, EQ, EQ);
        !          8468:       break;
        !          8469: 
        !          8470:     case NE_EXPR:
        !          8471:       if (integer_zerop (TREE_OPERAND (exp, 1)))
        !          8472:        do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
        !          8473:       else if (((GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
        !          8474:                 == MODE_INT)
        !          8475:                && 
        !          8476:                !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
        !          8477:               || GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))) == MODE_COMPLEX_FLOAT
        !          8478:               || GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))) == MODE_COMPLEX_INT)
        !          8479:        do_jump_by_parts_equality (exp, if_true_label, if_false_label);
        !          8480:       else
        !          8481:        comparison = compare (exp, NE, NE);
        !          8482:       break;
        !          8483: 
        !          8484:     case LT_EXPR:
        !          8485:       if ((GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
        !          8486:           == MODE_INT)
        !          8487:          && !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
        !          8488:        do_jump_by_parts_greater (exp, 1, if_false_label, if_true_label);
        !          8489:       else
        !          8490:        comparison = compare (exp, LT, LTU);
        !          8491:       break;
        !          8492: 
        !          8493:     case LE_EXPR:
        !          8494:       if ((GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
        !          8495:           == MODE_INT)
        !          8496:          && !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
        !          8497:        do_jump_by_parts_greater (exp, 0, if_true_label, if_false_label);
        !          8498:       else
        !          8499:        comparison = compare (exp, LE, LEU);
        !          8500:       break;
        !          8501: 
        !          8502:     case GT_EXPR:
        !          8503:       if ((GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
        !          8504:           == MODE_INT)
        !          8505:          && !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
        !          8506:        do_jump_by_parts_greater (exp, 0, if_false_label, if_true_label);
        !          8507:       else
        !          8508:        comparison = compare (exp, GT, GTU);
        !          8509:       break;
        !          8510: 
        !          8511:     case GE_EXPR:
        !          8512:       if ((GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
        !          8513:           == MODE_INT)
        !          8514:          && !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
        !          8515:        do_jump_by_parts_greater (exp, 1, if_true_label, if_false_label);
        !          8516:       else
        !          8517:        comparison = compare (exp, GE, GEU);
        !          8518:       break;
        !          8519: 
        !          8520:     default:
        !          8521:     normal:
        !          8522:       temp = expand_expr (exp, NULL_RTX, VOIDmode, 0);
        !          8523: #if 0
        !          8524:       /* This is not needed any more and causes poor code since it causes
        !          8525:         comparisons and tests from non-SI objects to have different code
        !          8526:         sequences.  */
        !          8527:       /* Copy to register to avoid generating bad insns by cse
        !          8528:         from (set (mem ...) (arithop))  (set (cc0) (mem ...)).  */
        !          8529:       if (!cse_not_expected && GET_CODE (temp) == MEM)
        !          8530:        temp = copy_to_reg (temp);
        !          8531: #endif
        !          8532:       do_pending_stack_adjust ();
        !          8533:       if (GET_CODE (temp) == CONST_INT)
        !          8534:        comparison = (temp == const0_rtx ? const0_rtx : const_true_rtx);
        !          8535:       else if (GET_CODE (temp) == LABEL_REF)
        !          8536:        comparison = const_true_rtx;
        !          8537:       else if (GET_MODE_CLASS (GET_MODE (temp)) == MODE_INT
        !          8538:               && !can_compare_p (GET_MODE (temp)))
        !          8539:        /* Note swapping the labels gives us not-equal.  */
        !          8540:        do_jump_by_parts_equality_rtx (temp, if_true_label, if_false_label);
        !          8541:       else if (GET_MODE (temp) != VOIDmode)
        !          8542:        comparison = compare_from_rtx (temp, CONST0_RTX (GET_MODE (temp)),
        !          8543:                                       NE, TREE_UNSIGNED (TREE_TYPE (exp)),
        !          8544:                                       GET_MODE (temp), NULL_RTX, 0);
        !          8545:       else
        !          8546:        abort ();
        !          8547:     }
        !          8548: 
        !          8549:   /* Do any postincrements in the expression that was tested.  */
        !          8550:   emit_queue ();
        !          8551: 
        !          8552:   /* If COMPARISON is nonzero here, it is an rtx that can be substituted
        !          8553:      straight into a conditional jump instruction as the jump condition.
        !          8554:      Otherwise, all the work has been done already.  */
        !          8555: 
        !          8556:   if (comparison == const_true_rtx)
        !          8557:     {
        !          8558:       if (if_true_label)
        !          8559:        emit_jump (if_true_label);
        !          8560:     }
        !          8561:   else if (comparison == const0_rtx)
        !          8562:     {
        !          8563:       if (if_false_label)
        !          8564:        emit_jump (if_false_label);
        !          8565:     }
        !          8566:   else if (comparison)
        !          8567:     do_jump_for_compare (comparison, if_false_label, if_true_label);
        !          8568: 
        !          8569:   if (drop_through_label)
        !          8570:     {
        !          8571:       /* If do_jump produces code that might be jumped around,
        !          8572:         do any stack adjusts from that code, before the place
        !          8573:         where control merges in.  */
        !          8574:       do_pending_stack_adjust ();
        !          8575:       emit_label (drop_through_label);
        !          8576:     }
        !          8577: }
        !          8578: 
        !          8579: /* Given a comparison expression EXP for values too wide to be compared
        !          8580:    with one insn, test the comparison and jump to the appropriate label.
        !          8581:    The code of EXP is ignored; we always test GT if SWAP is 0,
        !          8582:    and LT if SWAP is 1.  */
        !          8583: 
        !          8584: static void
        !          8585: do_jump_by_parts_greater (exp, swap, if_false_label, if_true_label)
        !          8586:      tree exp;
        !          8587:      int swap;
        !          8588:      rtx if_false_label, if_true_label;
        !          8589: {
        !          8590:   rtx op0 = expand_expr (TREE_OPERAND (exp, swap), NULL_RTX, VOIDmode, 0);
        !          8591:   rtx op1 = expand_expr (TREE_OPERAND (exp, !swap), NULL_RTX, VOIDmode, 0);
        !          8592:   enum machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
        !          8593:   int nwords = (GET_MODE_SIZE (mode) / UNITS_PER_WORD);
        !          8594:   rtx drop_through_label = 0;
        !          8595:   int unsignedp = TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0)));
        !          8596:   int i;
        !          8597: 
        !          8598:   if (! if_true_label || ! if_false_label)
        !          8599:     drop_through_label = gen_label_rtx ();
        !          8600:   if (! if_true_label)
        !          8601:     if_true_label = drop_through_label;
        !          8602:   if (! if_false_label)
        !          8603:     if_false_label = drop_through_label;
        !          8604: 
        !          8605:   /* Compare a word at a time, high order first.  */
        !          8606:   for (i = 0; i < nwords; i++)
        !          8607:     {
        !          8608:       rtx comp;
        !          8609:       rtx op0_word, op1_word;
        !          8610: 
        !          8611:       if (WORDS_BIG_ENDIAN)
        !          8612:        {
        !          8613:          op0_word = operand_subword_force (op0, i, mode);
        !          8614:          op1_word = operand_subword_force (op1, i, mode);
        !          8615:        }
        !          8616:       else
        !          8617:        {
        !          8618:          op0_word = operand_subword_force (op0, nwords - 1 - i, mode);
        !          8619:          op1_word = operand_subword_force (op1, nwords - 1 - i, mode);
        !          8620:        }
        !          8621: 
        !          8622:       /* All but high-order word must be compared as unsigned.  */
        !          8623:       comp = compare_from_rtx (op0_word, op1_word,
        !          8624:                               (unsignedp || i > 0) ? GTU : GT,
        !          8625:                               unsignedp, word_mode, NULL_RTX, 0);
        !          8626:       if (comp == const_true_rtx)
        !          8627:        emit_jump (if_true_label);
        !          8628:       else if (comp != const0_rtx)
        !          8629:        do_jump_for_compare (comp, NULL_RTX, if_true_label);
        !          8630: 
        !          8631:       /* Consider lower words only if these are equal.  */
        !          8632:       comp = compare_from_rtx (op0_word, op1_word, NE, unsignedp, word_mode,
        !          8633:                               NULL_RTX, 0);
        !          8634:       if (comp == const_true_rtx)
        !          8635:        emit_jump (if_false_label);
        !          8636:       else if (comp != const0_rtx)
        !          8637:        do_jump_for_compare (comp, NULL_RTX, if_false_label);
        !          8638:     }
        !          8639: 
        !          8640:   if (if_false_label)
        !          8641:     emit_jump (if_false_label);
        !          8642:   if (drop_through_label)
        !          8643:     emit_label (drop_through_label);
        !          8644: }
        !          8645: 
        !          8646: /* Compare OP0 with OP1, word at a time, in mode MODE.
        !          8647:    UNSIGNEDP says to do unsigned comparison.
        !          8648:    Jump to IF_TRUE_LABEL if OP0 is greater, IF_FALSE_LABEL otherwise.  */
        !          8649: 
        !          8650: static void
        !          8651: do_jump_by_parts_greater_rtx (mode, unsignedp, op0, op1, if_false_label, if_true_label)
        !          8652:      enum machine_mode mode;
        !          8653:      int unsignedp;
        !          8654:      rtx op0, op1;
        !          8655:      rtx if_false_label, if_true_label;
        !          8656: {
        !          8657:   int nwords = (GET_MODE_SIZE (mode) / UNITS_PER_WORD);
        !          8658:   rtx drop_through_label = 0;
        !          8659:   int i;
        !          8660: 
        !          8661:   if (! if_true_label || ! if_false_label)
        !          8662:     drop_through_label = gen_label_rtx ();
        !          8663:   if (! if_true_label)
        !          8664:     if_true_label = drop_through_label;
        !          8665:   if (! if_false_label)
        !          8666:     if_false_label = drop_through_label;
        !          8667: 
        !          8668:   /* Compare a word at a time, high order first.  */
        !          8669:   for (i = 0; i < nwords; i++)
        !          8670:     {
        !          8671:       rtx comp;
        !          8672:       rtx op0_word, op1_word;
        !          8673: 
        !          8674:       if (WORDS_BIG_ENDIAN)
        !          8675:        {
        !          8676:          op0_word = operand_subword_force (op0, i, mode);
        !          8677:          op1_word = operand_subword_force (op1, i, mode);
        !          8678:        }
        !          8679:       else
        !          8680:        {
        !          8681:          op0_word = operand_subword_force (op0, nwords - 1 - i, mode);
        !          8682:          op1_word = operand_subword_force (op1, nwords - 1 - i, mode);
        !          8683:        }
        !          8684: 
        !          8685:       /* All but high-order word must be compared as unsigned.  */
        !          8686:       comp = compare_from_rtx (op0_word, op1_word,
        !          8687:                               (unsignedp || i > 0) ? GTU : GT,
        !          8688:                               unsignedp, word_mode, NULL_RTX, 0);
        !          8689:       if (comp == const_true_rtx)
        !          8690:        emit_jump (if_true_label);
        !          8691:       else if (comp != const0_rtx)
        !          8692:        do_jump_for_compare (comp, NULL_RTX, if_true_label);
        !          8693: 
        !          8694:       /* Consider lower words only if these are equal.  */
        !          8695:       comp = compare_from_rtx (op0_word, op1_word, NE, unsignedp, word_mode,
        !          8696:                               NULL_RTX, 0);
        !          8697:       if (comp == const_true_rtx)
        !          8698:        emit_jump (if_false_label);
        !          8699:       else if (comp != const0_rtx)
        !          8700:        do_jump_for_compare (comp, NULL_RTX, if_false_label);
        !          8701:     }
        !          8702: 
        !          8703:   if (if_false_label)
        !          8704:     emit_jump (if_false_label);
        !          8705:   if (drop_through_label)
        !          8706:     emit_label (drop_through_label);
        !          8707: }
        !          8708: 
        !          8709: /* Given an EQ_EXPR expression EXP for values too wide to be compared
        !          8710:    with one insn, test the comparison and jump to the appropriate label.  */
        !          8711: 
        !          8712: static void
        !          8713: do_jump_by_parts_equality (exp, if_false_label, if_true_label)
        !          8714:      tree exp;
        !          8715:      rtx if_false_label, if_true_label;
        !          8716: {
        !          8717:   rtx op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
        !          8718:   rtx op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
        !          8719:   enum machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
        !          8720:   int nwords = (GET_MODE_SIZE (mode) / UNITS_PER_WORD);
        !          8721:   int i;
        !          8722:   rtx drop_through_label = 0;
        !          8723: 
        !          8724:   if (! if_false_label)
        !          8725:     drop_through_label = if_false_label = gen_label_rtx ();
        !          8726: 
        !          8727:   for (i = 0; i < nwords; i++)
        !          8728:     {
        !          8729:       rtx comp = compare_from_rtx (operand_subword_force (op0, i, mode),
        !          8730:                                   operand_subword_force (op1, i, mode),
        !          8731:                                   EQ, TREE_UNSIGNED (TREE_TYPE (exp)),
        !          8732:                                   word_mode, NULL_RTX, 0);
        !          8733:       if (comp == const_true_rtx)
        !          8734:        emit_jump (if_false_label);
        !          8735:       else if (comp != const0_rtx)
        !          8736:        do_jump_for_compare (comp, if_false_label, NULL_RTX);
        !          8737:     }
        !          8738: 
        !          8739:   if (if_true_label)
        !          8740:     emit_jump (if_true_label);
        !          8741:   if (drop_through_label)
        !          8742:     emit_label (drop_through_label);
        !          8743: }
        !          8744: 
        !          8745: /* Jump according to whether OP0 is 0.
        !          8746:    We assume that OP0 has an integer mode that is too wide
        !          8747:    for the available compare insns.  */
        !          8748: 
        !          8749: static void
        !          8750: do_jump_by_parts_equality_rtx (op0, if_false_label, if_true_label)
        !          8751:      rtx op0;
        !          8752:      rtx if_false_label, if_true_label;
        !          8753: {
        !          8754:   int nwords = GET_MODE_SIZE (GET_MODE (op0)) / UNITS_PER_WORD;
        !          8755:   int i;
        !          8756:   rtx drop_through_label = 0;
        !          8757: 
        !          8758:   if (! if_false_label)
        !          8759:     drop_through_label = if_false_label = gen_label_rtx ();
        !          8760: 
        !          8761:   for (i = 0; i < nwords; i++)
        !          8762:     {
        !          8763:       rtx comp = compare_from_rtx (operand_subword_force (op0, i,
        !          8764:                                                          GET_MODE (op0)),
        !          8765:                                   const0_rtx, EQ, 1, word_mode, NULL_RTX, 0);
        !          8766:       if (comp == const_true_rtx)
        !          8767:        emit_jump (if_false_label);
        !          8768:       else if (comp != const0_rtx)
        !          8769:        do_jump_for_compare (comp, if_false_label, NULL_RTX);
        !          8770:     }
        !          8771: 
        !          8772:   if (if_true_label)
        !          8773:     emit_jump (if_true_label);
        !          8774:   if (drop_through_label)
        !          8775:     emit_label (drop_through_label);
        !          8776: }
        !          8777: 
        !          8778: /* Given a comparison expression in rtl form, output conditional branches to
        !          8779:    IF_TRUE_LABEL, IF_FALSE_LABEL, or both.  */
        !          8780: 
        !          8781: static void
        !          8782: do_jump_for_compare (comparison, if_false_label, if_true_label)
        !          8783:      rtx comparison, if_false_label, if_true_label;
        !          8784: {
        !          8785:   if (if_true_label)
        !          8786:     {
        !          8787:       if (bcc_gen_fctn[(int) GET_CODE (comparison)] != 0)
        !          8788:        emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (comparison)]) (if_true_label));
        !          8789:       else
        !          8790:        abort ();
        !          8791: 
        !          8792:       if (if_false_label)
        !          8793:        emit_jump (if_false_label);
        !          8794:     }
        !          8795:   else if (if_false_label)
        !          8796:     {
        !          8797:       rtx insn;
        !          8798:       rtx prev = get_last_insn ();
        !          8799:       rtx branch = 0;
        !          8800: 
        !          8801:       if (prev != 0)
        !          8802:        prev = PREV_INSN (prev);
        !          8803: 
        !          8804:       /* Output the branch with the opposite condition.  Then try to invert
        !          8805:         what is generated.  If more than one insn is a branch, or if the
        !          8806:         branch is not the last insn written, abort. If we can't invert
        !          8807:         the branch, emit make a true label, redirect this jump to that,
        !          8808:         emit a jump to the false label and define the true label.  */
        !          8809: 
        !          8810:       if (bcc_gen_fctn[(int) GET_CODE (comparison)] != 0)
        !          8811:        emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (comparison)]) (if_false_label));
        !          8812:       else
        !          8813:        abort ();
        !          8814: 
        !          8815:       /* Here we get the insn before what was just emitted.
        !          8816:         On some machines, emitting the branch can discard
        !          8817:         the previous compare insn and emit a replacement.  */
        !          8818:       if (prev == 0)
        !          8819:        /* If there's only one preceding insn...  */
        !          8820:        insn = get_insns ();
        !          8821:       else
        !          8822:        insn = NEXT_INSN (prev);
        !          8823: 
        !          8824:       for (insn = NEXT_INSN (insn); insn; insn = NEXT_INSN (insn))
        !          8825:        if (GET_CODE (insn) == JUMP_INSN)
        !          8826:          {
        !          8827:            if (branch)
        !          8828:              abort ();
        !          8829:            branch = insn;
        !          8830:          }
        !          8831: 
        !          8832:       if (branch != get_last_insn ())
        !          8833:        abort ();
        !          8834: 
        !          8835:       if (! invert_jump (branch, if_false_label))
        !          8836:        {
        !          8837:          if_true_label = gen_label_rtx ();
        !          8838:          redirect_jump (branch, if_true_label);
        !          8839:          emit_jump (if_false_label);
        !          8840:          emit_label (if_true_label);
        !          8841:        }
        !          8842:     }
        !          8843: }
        !          8844: 
        !          8845: /* Generate code for a comparison expression EXP
        !          8846:    (including code to compute the values to be compared)
        !          8847:    and set (CC0) according to the result.
        !          8848:    SIGNED_CODE should be the rtx operation for this comparison for
        !          8849:    signed data; UNSIGNED_CODE, likewise for use if data is unsigned.
        !          8850: 
        !          8851:    We force a stack adjustment unless there are currently
        !          8852:    things pushed on the stack that aren't yet used.  */
        !          8853: 
        !          8854: static rtx
        !          8855: compare (exp, signed_code, unsigned_code)
        !          8856:      register tree exp;
        !          8857:      enum rtx_code signed_code, unsigned_code;
        !          8858: {
        !          8859:   register rtx op0
        !          8860:     = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
        !          8861:   register rtx op1
        !          8862:     = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
        !          8863:   register tree type = TREE_TYPE (TREE_OPERAND (exp, 0));
        !          8864:   register enum machine_mode mode = TYPE_MODE (type);
        !          8865:   int unsignedp = TREE_UNSIGNED (type);
        !          8866:   enum rtx_code code = unsignedp ? unsigned_code : signed_code;
        !          8867: 
        !          8868:   return compare_from_rtx (op0, op1, code, unsignedp, mode,
        !          8869:                           ((mode == BLKmode)
        !          8870:                            ? expr_size (TREE_OPERAND (exp, 0)) : NULL_RTX),
        !          8871:                           TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
        !          8872: }
        !          8873: 
        !          8874: /* Like compare but expects the values to compare as two rtx's.
        !          8875:    The decision as to signed or unsigned comparison must be made by the caller.
        !          8876: 
        !          8877:    If MODE is BLKmode, SIZE is an RTX giving the size of the objects being
        !          8878:    compared.
        !          8879: 
        !          8880:    If ALIGN is non-zero, it is the alignment of this type; if zero, the
        !          8881:    size of MODE should be used.  */
        !          8882: 
        !          8883: rtx
        !          8884: compare_from_rtx (op0, op1, code, unsignedp, mode, size, align)
        !          8885:      register rtx op0, op1;
        !          8886:      enum rtx_code code;
        !          8887:      int unsignedp;
        !          8888:      enum machine_mode mode;
        !          8889:      rtx size;
        !          8890:      int align;
        !          8891: {
        !          8892:   rtx tem;
        !          8893: 
        !          8894:   /* If one operand is constant, make it the second one.  Only do this
        !          8895:      if the other operand is not constant as well.  */
        !          8896: 
        !          8897:   if ((CONSTANT_P (op0) && ! CONSTANT_P (op1))
        !          8898:       || (GET_CODE (op0) == CONST_INT && GET_CODE (op1) != CONST_INT))
        !          8899:     {
        !          8900:       tem = op0;
        !          8901:       op0 = op1;
        !          8902:       op1 = tem;
        !          8903:       code = swap_condition (code);
        !          8904:     }
        !          8905: 
        !          8906:   if (flag_force_mem)
        !          8907:     {
        !          8908:       op0 = force_not_mem (op0);
        !          8909:       op1 = force_not_mem (op1);
        !          8910:     }
        !          8911: 
        !          8912:   do_pending_stack_adjust ();
        !          8913: 
        !          8914:   if (GET_CODE (op0) == CONST_INT && GET_CODE (op1) == CONST_INT
        !          8915:       && (tem = simplify_relational_operation (code, mode, op0, op1)) != 0)
        !          8916:     return tem;
        !          8917: 
        !          8918: #if 0
        !          8919:   /* There's no need to do this now that combine.c can eliminate lots of
        !          8920:      sign extensions.  This can be less efficient in certain cases on other
        !          8921:      machines. */
        !          8922: 
        !          8923:   /* If this is a signed equality comparison, we can do it as an
        !          8924:      unsigned comparison since zero-extension is cheaper than sign
        !          8925:      extension and comparisons with zero are done as unsigned.  This is
        !          8926:      the case even on machines that can do fast sign extension, since
        !          8927:      zero-extension is easier to combine with other operations than
        !          8928:      sign-extension is.  If we are comparing against a constant, we must
        !          8929:      convert it to what it would look like unsigned.  */
        !          8930:   if ((code == EQ || code == NE) && ! unsignedp
        !          8931:       && GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT)
        !          8932:     {
        !          8933:       if (GET_CODE (op1) == CONST_INT
        !          8934:          && (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0))) != INTVAL (op1))
        !          8935:        op1 = GEN_INT (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0)));
        !          8936:       unsignedp = 1;
        !          8937:     }
        !          8938: #endif
        !          8939:        
        !          8940:   emit_cmp_insn (op0, op1, code, size, mode, unsignedp, align);
        !          8941: 
        !          8942:   return gen_rtx (code, VOIDmode, cc0_rtx, const0_rtx);
        !          8943: }
        !          8944: 
        !          8945: /* Generate code to calculate EXP using a store-flag instruction
        !          8946:    and return an rtx for the result.  EXP is either a comparison
        !          8947:    or a TRUTH_NOT_EXPR whose operand is a comparison.
        !          8948: 
        !          8949:    If TARGET is nonzero, store the result there if convenient.
        !          8950: 
        !          8951:    If ONLY_CHEAP is non-zero, only do this if it is likely to be very
        !          8952:    cheap.
        !          8953: 
        !          8954:    Return zero if there is no suitable set-flag instruction
        !          8955:    available on this machine.
        !          8956: 
        !          8957:    Once expand_expr has been called on the arguments of the comparison,
        !          8958:    we are committed to doing the store flag, since it is not safe to
        !          8959:    re-evaluate the expression.  We emit the store-flag insn by calling
        !          8960:    emit_store_flag, but only expand the arguments if we have a reason
        !          8961:    to believe that emit_store_flag will be successful.  If we think that
        !          8962:    it will, but it isn't, we have to simulate the store-flag with a
        !          8963:    set/jump/set sequence.  */
        !          8964: 
        !          8965: static rtx
        !          8966: do_store_flag (exp, target, mode, only_cheap)
        !          8967:      tree exp;
        !          8968:      rtx target;
        !          8969:      enum machine_mode mode;
        !          8970:      int only_cheap;
        !          8971: {
        !          8972:   enum rtx_code code;
        !          8973:   tree arg0, arg1, type;
        !          8974:   tree tem;
        !          8975:   enum machine_mode operand_mode;
        !          8976:   int invert = 0;
        !          8977:   int unsignedp;
        !          8978:   rtx op0, op1;
        !          8979:   enum insn_code icode;
        !          8980:   rtx subtarget = target;
        !          8981:   rtx result, label, pattern, jump_pat;
        !          8982: 
        !          8983:   /* If this is a TRUTH_NOT_EXPR, set a flag indicating we must invert the
        !          8984:      result at the end.  We can't simply invert the test since it would
        !          8985:      have already been inverted if it were valid.  This case occurs for
        !          8986:      some floating-point comparisons.  */
        !          8987: 
        !          8988:   if (TREE_CODE (exp) == TRUTH_NOT_EXPR)
        !          8989:     invert = 1, exp = TREE_OPERAND (exp, 0);
        !          8990: 
        !          8991:   arg0 = TREE_OPERAND (exp, 0);
        !          8992:   arg1 = TREE_OPERAND (exp, 1);
        !          8993:   type = TREE_TYPE (arg0);
        !          8994:   operand_mode = TYPE_MODE (type);
        !          8995:   unsignedp = TREE_UNSIGNED (type);
        !          8996: 
        !          8997:   /* We won't bother with BLKmode store-flag operations because it would mean
        !          8998:      passing a lot of information to emit_store_flag.  */
        !          8999:   if (operand_mode == BLKmode)
        !          9000:     return 0;
        !          9001: 
        !          9002:   STRIP_NOPS (arg0);
        !          9003:   STRIP_NOPS (arg1);
        !          9004: 
        !          9005:   /* Get the rtx comparison code to use.  We know that EXP is a comparison
        !          9006:      operation of some type.  Some comparisons against 1 and -1 can be
        !          9007:      converted to comparisons with zero.  Do so here so that the tests
        !          9008:      below will be aware that we have a comparison with zero.   These
        !          9009:      tests will not catch constants in the first operand, but constants
        !          9010:      are rarely passed as the first operand.  */
        !          9011: 
        !          9012:   switch (TREE_CODE (exp))
        !          9013:     {
        !          9014:     case EQ_EXPR:
        !          9015:       code = EQ;
        !          9016:       break;
        !          9017:     case NE_EXPR:
        !          9018:       code = NE;
        !          9019:       break;
        !          9020:     case LT_EXPR:
        !          9021:       if (integer_onep (arg1))
        !          9022:        arg1 = integer_zero_node, code = unsignedp ? LEU : LE;
        !          9023:       else
        !          9024:        code = unsignedp ? LTU : LT;
        !          9025:       break;
        !          9026:     case LE_EXPR:
        !          9027:       if (! unsignedp && integer_all_onesp (arg1))
        !          9028:        arg1 = integer_zero_node, code = LT;
        !          9029:       else
        !          9030:        code = unsignedp ? LEU : LE;
        !          9031:       break;
        !          9032:     case GT_EXPR:
        !          9033:       if (! unsignedp && integer_all_onesp (arg1))
        !          9034:        arg1 = integer_zero_node, code = GE;
        !          9035:       else
        !          9036:        code = unsignedp ? GTU : GT;
        !          9037:       break;
        !          9038:     case GE_EXPR:
        !          9039:       if (integer_onep (arg1))
        !          9040:        arg1 = integer_zero_node, code = unsignedp ? GTU : GT;
        !          9041:       else
        !          9042:        code = unsignedp ? GEU : GE;
        !          9043:       break;
        !          9044:     default:
        !          9045:       abort ();
        !          9046:     }
        !          9047: 
        !          9048:   /* Put a constant second.  */
        !          9049:   if (TREE_CODE (arg0) == REAL_CST || TREE_CODE (arg0) == INTEGER_CST)
        !          9050:     {
        !          9051:       tem = arg0; arg0 = arg1; arg1 = tem;
        !          9052:       code = swap_condition (code);
        !          9053:     }
        !          9054: 
        !          9055:   /* If this is an equality or inequality test of a single bit, we can
        !          9056:      do this by shifting the bit being tested to the low-order bit and
        !          9057:      masking the result with the constant 1.  If the condition was EQ,
        !          9058:      we xor it with 1.  This does not require an scc insn and is faster
        !          9059:      than an scc insn even if we have it.  */
        !          9060: 
        !          9061:   if ((code == NE || code == EQ)
        !          9062:       && TREE_CODE (arg0) == BIT_AND_EXPR && integer_zerop (arg1)
        !          9063:       && integer_pow2p (TREE_OPERAND (arg0, 1))
        !          9064:       && TYPE_PRECISION (type) <= HOST_BITS_PER_WIDE_INT)
        !          9065:     {
        !          9066:       tree inner = TREE_OPERAND (arg0, 0);
        !          9067:       int bitnum = exact_log2 (INTVAL (expand_expr (TREE_OPERAND (arg0, 1),
        !          9068:                                                    NULL_RTX, VOIDmode, 0)));
        !          9069:       int ops_unsignedp;
        !          9070: 
        !          9071:       /* If INNER is a right shift of a constant and it plus BITNUM does
        !          9072:         not overflow, adjust BITNUM and INNER.  */
        !          9073: 
        !          9074:       if (TREE_CODE (inner) == RSHIFT_EXPR
        !          9075:          && TREE_CODE (TREE_OPERAND (inner, 1)) == INTEGER_CST
        !          9076:          && TREE_INT_CST_HIGH (TREE_OPERAND (inner, 1)) == 0
        !          9077:          && (bitnum + TREE_INT_CST_LOW (TREE_OPERAND (inner, 1))
        !          9078:              < TYPE_PRECISION (type)))
        !          9079:        {
        !          9080:          bitnum +=TREE_INT_CST_LOW (TREE_OPERAND (inner, 1));
        !          9081:          inner = TREE_OPERAND (inner, 0);
        !          9082:        }
        !          9083: 
        !          9084:       /* If we are going to be able to omit the AND below, we must do our
        !          9085:         operations as unsigned.  If we must use the AND, we have a choice.
        !          9086:         Normally unsigned is faster, but for some machines signed is.  */
        !          9087:       ops_unsignedp = (bitnum == TYPE_PRECISION (type) - 1 ? 1
        !          9088: #ifdef LOAD_EXTEND_OP
        !          9089:                       : (LOAD_EXTEND_OP (operand_mode) == SIGN_EXTEND ? 0 : 1)
        !          9090: #else
        !          9091:                       : 1
        !          9092: #endif
        !          9093:                       );
        !          9094: 
        !          9095:       if (subtarget == 0 || GET_CODE (subtarget) != REG
        !          9096:          || GET_MODE (subtarget) != operand_mode
        !          9097:          || ! safe_from_p (subtarget, inner))
        !          9098:        subtarget = 0;
        !          9099: 
        !          9100:       op0 = expand_expr (inner, subtarget, VOIDmode, 0);
        !          9101: 
        !          9102:       if (bitnum != 0)
        !          9103:        op0 = expand_shift (RSHIFT_EXPR, GET_MODE (op0), op0,
        !          9104:                            size_int (bitnum), subtarget, ops_unsignedp);
        !          9105: 
        !          9106:       if (GET_MODE (op0) != mode)
        !          9107:        op0 = convert_to_mode (mode, op0, ops_unsignedp);
        !          9108: 
        !          9109:       if ((code == EQ && ! invert) || (code == NE && invert))
        !          9110:        op0 = expand_binop (mode, xor_optab, op0, const1_rtx, subtarget,
        !          9111:                            ops_unsignedp, OPTAB_LIB_WIDEN);
        !          9112: 
        !          9113:       /* Put the AND last so it can combine with more things.  */
        !          9114:       if (bitnum != TYPE_PRECISION (type) - 1)
        !          9115:        op0 = expand_and (op0, const1_rtx, subtarget);
        !          9116: 
        !          9117:       return op0;
        !          9118:     }
        !          9119: 
        !          9120:   /* Now see if we are likely to be able to do this.  Return if not.  */
        !          9121:   if (! can_compare_p (operand_mode))
        !          9122:     return 0;
        !          9123:   icode = setcc_gen_code[(int) code];
        !          9124:   if (icode == CODE_FOR_nothing
        !          9125:       || (only_cheap && insn_operand_mode[(int) icode][0] != mode))
        !          9126:     {
        !          9127:       /* We can only do this if it is one of the special cases that
        !          9128:         can be handled without an scc insn.  */
        !          9129:       if ((code == LT && integer_zerop (arg1))
        !          9130:          || (! only_cheap && code == GE && integer_zerop (arg1)))
        !          9131:        ;
        !          9132:       else if (BRANCH_COST >= 0
        !          9133:               && ! only_cheap && (code == NE || code == EQ)
        !          9134:               && TREE_CODE (type) != REAL_TYPE
        !          9135:               && ((abs_optab->handlers[(int) operand_mode].insn_code
        !          9136:                    != CODE_FOR_nothing)
        !          9137:                   || (ffs_optab->handlers[(int) operand_mode].insn_code
        !          9138:                       != CODE_FOR_nothing)))
        !          9139:        ;
        !          9140:       else
        !          9141:        return 0;
        !          9142:     }
        !          9143:       
        !          9144:   preexpand_calls (exp);
        !          9145:   if (subtarget == 0 || GET_CODE (subtarget) != REG
        !          9146:       || GET_MODE (subtarget) != operand_mode
        !          9147:       || ! safe_from_p (subtarget, arg1))
        !          9148:     subtarget = 0;
        !          9149: 
        !          9150:   op0 = expand_expr (arg0, subtarget, VOIDmode, 0);
        !          9151:   op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
        !          9152: 
        !          9153:   if (target == 0)
        !          9154:     target = gen_reg_rtx (mode);
        !          9155: 
        !          9156:   /* Pass copies of OP0 and OP1 in case they contain a QUEUED.  This is safe
        !          9157:      because, if the emit_store_flag does anything it will succeed and
        !          9158:      OP0 and OP1 will not be used subsequently.  */
        !          9159: 
        !          9160:   result = emit_store_flag (target, code,
        !          9161:                            queued_subexp_p (op0) ? copy_rtx (op0) : op0,
        !          9162:                            queued_subexp_p (op1) ? copy_rtx (op1) : op1,
        !          9163:                            operand_mode, unsignedp, 1);
        !          9164: 
        !          9165:   if (result)
        !          9166:     {
        !          9167:       if (invert)
        !          9168:        result = expand_binop (mode, xor_optab, result, const1_rtx,
        !          9169:                               result, 0, OPTAB_LIB_WIDEN);
        !          9170:       return result;
        !          9171:     }
        !          9172: 
        !          9173:   /* If this failed, we have to do this with set/compare/jump/set code.  */
        !          9174:   if (target == 0 || GET_CODE (target) != REG
        !          9175:       || reg_mentioned_p (target, op0) || reg_mentioned_p (target, op1))
        !          9176:     target = gen_reg_rtx (GET_MODE (target));
        !          9177: 
        !          9178:   emit_move_insn (target, invert ? const0_rtx : const1_rtx);
        !          9179:   result = compare_from_rtx (op0, op1, code, unsignedp,
        !          9180:                             operand_mode, NULL_RTX, 0);
        !          9181:   if (GET_CODE (result) == CONST_INT)
        !          9182:     return (((result == const0_rtx && ! invert)
        !          9183:             || (result != const0_rtx && invert))
        !          9184:            ? const0_rtx : const1_rtx);
        !          9185: 
        !          9186:   label = gen_label_rtx ();
        !          9187:   if (bcc_gen_fctn[(int) code] == 0)
        !          9188:     abort ();
        !          9189: 
        !          9190:   emit_jump_insn ((*bcc_gen_fctn[(int) code]) (label));
        !          9191:   emit_move_insn (target, invert ? const1_rtx : const0_rtx);
        !          9192:   emit_label (label);
        !          9193: 
        !          9194:   return target;
        !          9195: }
        !          9196: 
        !          9197: /* Generate a tablejump instruction (used for switch statements).  */
        !          9198: 
        !          9199: #ifdef HAVE_tablejump
        !          9200: 
        !          9201: /* INDEX is the value being switched on, with the lowest value
        !          9202:    in the table already subtracted.
        !          9203:    MODE is its expected mode (needed if INDEX is constant).
        !          9204:    RANGE is the length of the jump table.
        !          9205:    TABLE_LABEL is a CODE_LABEL rtx for the table itself.
        !          9206: 
        !          9207:    DEFAULT_LABEL is a CODE_LABEL rtx to jump to if the
        !          9208:    index value is out of range.  */
        !          9209: 
        !          9210: void
        !          9211: do_tablejump (index, mode, range, table_label, default_label)
        !          9212:      rtx index, range, table_label, default_label;
        !          9213:      enum machine_mode mode;
        !          9214: {
        !          9215:   register rtx temp, vector;
        !          9216: 
        !          9217:   /* Do an unsigned comparison (in the proper mode) between the index
        !          9218:      expression and the value which represents the length of the range.
        !          9219:      Since we just finished subtracting the lower bound of the range
        !          9220:      from the index expression, this comparison allows us to simultaneously
        !          9221:      check that the original index expression value is both greater than
        !          9222:      or equal to the minimum value of the range and less than or equal to
        !          9223:      the maximum value of the range.  */
        !          9224: 
        !          9225:   emit_cmp_insn (range, index, LTU, NULL_RTX, mode, 1, 0);
        !          9226:   emit_jump_insn (gen_bltu (default_label));
        !          9227: 
        !          9228:   /* If index is in range, it must fit in Pmode.
        !          9229:      Convert to Pmode so we can index with it.  */
        !          9230:   if (mode != Pmode)
        !          9231:     index = convert_to_mode (Pmode, index, 1);
        !          9232: 
        !          9233:   /* Don't let a MEM slip thru, because then INDEX that comes
        !          9234:      out of PIC_CASE_VECTOR_ADDRESS won't be a valid address,
        !          9235:      and break_out_memory_refs will go to work on it and mess it up.  */
        !          9236: #ifdef PIC_CASE_VECTOR_ADDRESS
        !          9237:   if (flag_pic && GET_CODE (index) != REG)
        !          9238:     index = copy_to_mode_reg (Pmode, index);
        !          9239: #endif
        !          9240: 
        !          9241:   /* If flag_force_addr were to affect this address
        !          9242:      it could interfere with the tricky assumptions made
        !          9243:      about addresses that contain label-refs,
        !          9244:      which may be valid only very near the tablejump itself.  */
        !          9245:   /* ??? The only correct use of CASE_VECTOR_MODE is the one inside the
        !          9246:      GET_MODE_SIZE, because this indicates how large insns are.  The other
        !          9247:      uses should all be Pmode, because they are addresses.  This code
        !          9248:      could fail if addresses and insns are not the same size.  */
        !          9249:   index = gen_rtx (PLUS, Pmode,
        !          9250:                   gen_rtx (MULT, Pmode, index,
        !          9251:                            GEN_INT (GET_MODE_SIZE (CASE_VECTOR_MODE))),
        !          9252:                   gen_rtx (LABEL_REF, Pmode, table_label));
        !          9253: #ifdef PIC_CASE_VECTOR_ADDRESS
        !          9254:   if (flag_pic)
        !          9255:     index = PIC_CASE_VECTOR_ADDRESS (index);
        !          9256:   else
        !          9257: #endif
        !          9258:     index = memory_address_noforce (CASE_VECTOR_MODE, index);
        !          9259:   temp = gen_reg_rtx (CASE_VECTOR_MODE);
        !          9260:   vector = gen_rtx (MEM, CASE_VECTOR_MODE, index);
        !          9261:   RTX_UNCHANGING_P (vector) = 1;
        !          9262:   convert_move (temp, vector, 0);
        !          9263: 
        !          9264:   emit_jump_insn (gen_tablejump (temp, table_label));
        !          9265: 
        !          9266: #ifndef CASE_VECTOR_PC_RELATIVE
        !          9267:   /* If we are generating PIC code or if the table is PC-relative, the
        !          9268:      table and JUMP_INSN must be adjacent, so don't output a BARRIER.  */
        !          9269:   if (! flag_pic)
        !          9270:     emit_barrier ();
        !          9271: #endif
        !          9272: }
        !          9273: 
        !          9274: #endif /* HAVE_tablejump */
        !          9275: 
        !          9276: 
        !          9277: /* Emit a suitable bytecode to load a value from memory, assuming a pointer
        !          9278:    to that value is on the top of the stack. The resulting type is TYPE, and
        !          9279:    the source declaration is DECL. */
        !          9280: 
        !          9281: void
        !          9282: bc_load_memory (type, decl)
        !          9283:      tree type, decl;
        !          9284: {
        !          9285:   enum bytecode_opcode opcode;
        !          9286:   
        !          9287:   
        !          9288:   /* Bit fields are special.  We only know about signed and
        !          9289:      unsigned ints, and enums.  The latter are treated as
        !          9290:      signed integers. */
        !          9291:   
        !          9292:   if (DECL_BIT_FIELD (decl))
        !          9293:     if (TREE_CODE (type) == ENUMERAL_TYPE
        !          9294:        || TREE_CODE (type) == INTEGER_TYPE)
        !          9295:       opcode = TREE_UNSIGNED (type) ? zxloadBI : sxloadBI;
        !          9296:     else
        !          9297:       abort ();
        !          9298:   else
        !          9299:     /* See corresponding comment in bc_store_memory(). */
        !          9300:     if (TYPE_MODE (type) == BLKmode
        !          9301:        || TYPE_MODE (type) == VOIDmode)
        !          9302:       return;
        !          9303:     else
        !          9304:       opcode = mode_to_load_map [(int) TYPE_MODE (type)];
        !          9305: 
        !          9306:   if (opcode == neverneverland)
        !          9307:     abort ();
        !          9308:   
        !          9309:   bc_emit_bytecode (opcode);
        !          9310:   
        !          9311: #ifdef DEBUG_PRINT_CODE
        !          9312:   fputc ('\n', stderr);
        !          9313: #endif
        !          9314: }
        !          9315: 
        !          9316: 
        !          9317: /* Store the contents of the second stack slot to the address in the
        !          9318:    top stack slot.  DECL is the declaration of the destination and is used
        !          9319:    to determine whether we're dealing with a bitfield. */
        !          9320: 
        !          9321: void
        !          9322: bc_store_memory (type, decl)
        !          9323:      tree type, decl;
        !          9324: {
        !          9325:   enum bytecode_opcode opcode;
        !          9326:   
        !          9327:   
        !          9328:   if (DECL_BIT_FIELD (decl))
        !          9329:     {
        !          9330:       if (TREE_CODE (type) == ENUMERAL_TYPE
        !          9331:          || TREE_CODE (type) == INTEGER_TYPE)
        !          9332:        opcode = sstoreBI;
        !          9333:       else
        !          9334:        abort ();
        !          9335:     }
        !          9336:   else
        !          9337:     if (TYPE_MODE (type) == BLKmode)
        !          9338:       {
        !          9339:        /* Copy structure.  This expands to a block copy instruction, storeBLK.
        !          9340:           In addition to the arguments expected by the other store instructions,
        !          9341:           it also expects a type size (SImode) on top of the stack, which is the
        !          9342:           structure size in size units (usually bytes).  The two first arguments
        !          9343:           are already on the stack; so we just put the size on level 1.  For some
        !          9344:           other languages, the size may be variable, this is why we don't encode
        !          9345:           it as a storeBLK literal, but rather treat it as a full-fledged expression. */
        !          9346:        
        !          9347:        bc_expand_expr (TYPE_SIZE (type));
        !          9348:        opcode = storeBLK;
        !          9349:       }
        !          9350:     else
        !          9351:       opcode = mode_to_store_map [(int) TYPE_MODE (type)];
        !          9352: 
        !          9353:   if (opcode == neverneverland)
        !          9354:     abort ();
        !          9355: 
        !          9356:   bc_emit_bytecode (opcode);
        !          9357:   
        !          9358: #ifdef DEBUG_PRINT_CODE
        !          9359:   fputc ('\n', stderr);
        !          9360: #endif
        !          9361: }
        !          9362: 
        !          9363: 
        !          9364: /* Allocate local stack space sufficient to hold a value of the given
        !          9365:    SIZE at alignment boundary ALIGNMENT bits.  ALIGNMENT must be an
        !          9366:    integral power of 2.  A special case is locals of type VOID, which
        !          9367:    have size 0 and alignment 1 - any "voidish" SIZE or ALIGNMENT is
        !          9368:    remapped into the corresponding attribute of SI.  */
        !          9369: 
        !          9370: rtx
        !          9371: bc_allocate_local (size, alignment)
        !          9372:      int size, alignment;
        !          9373: {
        !          9374:   rtx retval;
        !          9375:   int byte_alignment;
        !          9376: 
        !          9377:   if (size < 0)
        !          9378:     abort ();
        !          9379: 
        !          9380:   /* Normalize size and alignment  */
        !          9381:   if (!size)
        !          9382:     size = UNITS_PER_WORD;
        !          9383: 
        !          9384:   if (alignment < BITS_PER_UNIT)
        !          9385:     byte_alignment = 1 << (INT_ALIGN - 1);
        !          9386:   else
        !          9387:     /* Align */
        !          9388:     byte_alignment = alignment / BITS_PER_UNIT;
        !          9389: 
        !          9390:   if (local_vars_size & (byte_alignment - 1))
        !          9391:     local_vars_size += byte_alignment - (local_vars_size & (byte_alignment - 1));
        !          9392: 
        !          9393:   retval = bc_gen_rtx ((char *) 0, local_vars_size, (struct bc_label *) 0);
        !          9394:   local_vars_size += size;
        !          9395: 
        !          9396:   return retval;
        !          9397: }
        !          9398: 
        !          9399: 
        !          9400: /* Allocate variable-sized local array. Variable-sized arrays are
        !          9401:    actually pointers to the address in memory where they are stored. */
        !          9402: 
        !          9403: rtx
        !          9404: bc_allocate_variable_array (size)
        !          9405:      tree size;
        !          9406: {
        !          9407:   rtx retval;
        !          9408:   const int ptralign = (1 << (PTR_ALIGN - 1));
        !          9409: 
        !          9410:   /* Align pointer */
        !          9411:   if (local_vars_size & ptralign)
        !          9412:     local_vars_size +=  ptralign - (local_vars_size & ptralign);
        !          9413: 
        !          9414:   /* Note down local space needed: pointer to block; also return
        !          9415:      dummy rtx */
        !          9416: 
        !          9417:   retval = bc_gen_rtx ((char *) 0, local_vars_size, (struct bc_label *) 0);
        !          9418:   local_vars_size += POINTER_SIZE / BITS_PER_UNIT;
        !          9419:   return retval;
        !          9420: }
        !          9421: 
        !          9422: 
        !          9423: /* Push the machine address for the given external variable offset.  */
        !          9424: void
        !          9425: bc_load_externaddr (externaddr)
        !          9426:      rtx externaddr;
        !          9427: {
        !          9428:   bc_emit_bytecode (constP);
        !          9429:   bc_emit_code_labelref (BYTECODE_LABEL (externaddr),
        !          9430:                         BYTECODE_BC_LABEL (externaddr)->offset);
        !          9431: 
        !          9432: #ifdef DEBUG_PRINT_CODE
        !          9433:   fputc ('\n', stderr);
        !          9434: #endif
        !          9435: }
        !          9436: 
        !          9437: 
        !          9438: static char *
        !          9439: bc_strdup (s)
        !          9440:     char *s;
        !          9441: {
        !          9442:   char *new = (char *) xmalloc ((strlen (s) + 1) * sizeof *s);
        !          9443:   strcpy (new, s);
        !          9444:   return new;
        !          9445: }
        !          9446: 
        !          9447: 
        !          9448: /* Like above, but expects an IDENTIFIER.  */
        !          9449: void
        !          9450: bc_load_externaddr_id (id, offset)
        !          9451:      tree id;
        !          9452:      int offset;
        !          9453: {
        !          9454:   if (!IDENTIFIER_POINTER (id))
        !          9455:     abort ();
        !          9456: 
        !          9457:   bc_emit_bytecode (constP);
        !          9458:   bc_emit_code_labelref (bc_xstrdup (IDENTIFIER_POINTER (id)), offset);
        !          9459: 
        !          9460: #ifdef DEBUG_PRINT_CODE
        !          9461:   fputc ('\n', stderr);
        !          9462: #endif
        !          9463: }
        !          9464: 
        !          9465: 
        !          9466: /* Push the machine address for the given local variable offset.  */
        !          9467: void
        !          9468: bc_load_localaddr (localaddr)
        !          9469:      rtx localaddr;
        !          9470: {
        !          9471:   bc_emit_instruction (localP, (HOST_WIDE_INT) BYTECODE_BC_LABEL (localaddr)->offset);
        !          9472: }
        !          9473: 
        !          9474: 
        !          9475: /* Push the machine address for the given parameter offset.
        !          9476:    NOTE: offset is in bits. */
        !          9477: void
        !          9478: bc_load_parmaddr (parmaddr)
        !          9479:      rtx parmaddr;
        !          9480: {
        !          9481:   bc_emit_instruction (argP, ((HOST_WIDE_INT) BYTECODE_BC_LABEL (parmaddr)->offset
        !          9482:                              / BITS_PER_UNIT));
        !          9483: }
        !          9484: 
        !          9485: 
        !          9486: /* Convert a[i] into *(a + i).  */
        !          9487: tree
        !          9488: bc_canonicalize_array_ref (exp)
        !          9489:      tree exp;
        !          9490: {
        !          9491:   tree type = TREE_TYPE (exp);
        !          9492:   tree array_adr = build1 (ADDR_EXPR, TYPE_POINTER_TO (type),
        !          9493:                           TREE_OPERAND (exp, 0));
        !          9494:   tree index = TREE_OPERAND (exp, 1);
        !          9495: 
        !          9496: 
        !          9497:   /* Convert the integer argument to a type the same size as a pointer
        !          9498:      so the multiply won't overflow spuriously.  */
        !          9499: 
        !          9500:   if (TYPE_PRECISION (TREE_TYPE (index)) != POINTER_SIZE)
        !          9501:     index = convert (type_for_size (POINTER_SIZE, 0), index);
        !          9502: 
        !          9503:   /* The array address isn't volatile even if the array is.
        !          9504:      (Of course this isn't terribly relevant since the bytecode
        !          9505:      translator treats nearly everything as volatile anyway.)  */
        !          9506:   TREE_THIS_VOLATILE (array_adr) = 0;
        !          9507: 
        !          9508:   return build1 (INDIRECT_REF, type,
        !          9509:                 fold (build (PLUS_EXPR,
        !          9510:                              TYPE_POINTER_TO (type),
        !          9511:                              array_adr,
        !          9512:                              fold (build (MULT_EXPR,
        !          9513:                                           TYPE_POINTER_TO (type),
        !          9514:                                           index,
        !          9515:                                           size_in_bytes (type))))));
        !          9516: }
        !          9517: 
        !          9518: 
        !          9519: /* Load the address of the component referenced by the given
        !          9520:    COMPONENT_REF expression.
        !          9521: 
        !          9522:    Returns innermost lvalue. */
        !          9523: 
        !          9524: tree
        !          9525: bc_expand_component_address (exp)
        !          9526:      tree exp;
        !          9527: {
        !          9528:   tree tem, chain;
        !          9529:   enum machine_mode mode;
        !          9530:   int bitpos = 0;
        !          9531:   HOST_WIDE_INT SIval;
        !          9532: 
        !          9533: 
        !          9534:   tem = TREE_OPERAND (exp, 1);
        !          9535:   mode = DECL_MODE (tem);
        !          9536: 
        !          9537: 
        !          9538:   /* Compute cumulative bit offset for nested component refs
        !          9539:      and array refs, and find the ultimate containing object.  */
        !          9540: 
        !          9541:   for (tem = exp;; tem = TREE_OPERAND (tem, 0))
        !          9542:     {
        !          9543:       if (TREE_CODE (tem) == COMPONENT_REF)
        !          9544:        bitpos += TREE_INT_CST_LOW (DECL_FIELD_BITPOS (TREE_OPERAND (tem, 1)));
        !          9545:       else
        !          9546:        if (TREE_CODE (tem) == ARRAY_REF
        !          9547:            && TREE_CODE (TREE_OPERAND (tem, 1)) == INTEGER_CST
        !          9548:            && TREE_CODE (TYPE_SIZE (TREE_TYPE (tem))) == INTEGER_CST)
        !          9549: 
        !          9550:          bitpos += (TREE_INT_CST_LOW (TREE_OPERAND (tem, 1))
        !          9551:                     * TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (tem)))
        !          9552:                     /* * TYPE_SIZE_UNIT (TREE_TYPE (tem)) */);
        !          9553:        else
        !          9554:          break;
        !          9555:     }
        !          9556: 
        !          9557:   bc_expand_expr (tem);
        !          9558: 
        !          9559: 
        !          9560:   /* For bitfields also push their offset and size */
        !          9561:   if (DECL_BIT_FIELD (TREE_OPERAND (exp, 1)))
        !          9562:     bc_push_offset_and_size (bitpos, /* DECL_SIZE_UNIT */ (TREE_OPERAND (exp, 1)));
        !          9563:   else
        !          9564:     if (SIval = bitpos / BITS_PER_UNIT)
        !          9565:       bc_emit_instruction (addconstPSI, SIval);
        !          9566: 
        !          9567:   return (TREE_OPERAND (exp, 1));
        !          9568: }
        !          9569: 
        !          9570: 
        !          9571: /* Emit code to push two SI constants */
        !          9572: void
        !          9573: bc_push_offset_and_size (offset, size)
        !          9574:      HOST_WIDE_INT offset, size;
        !          9575: {
        !          9576:   bc_emit_instruction (constSI, offset);
        !          9577:   bc_emit_instruction (constSI, size);
        !          9578: }
        !          9579: 
        !          9580: 
        !          9581: /* Emit byte code to push the address of the given lvalue expression to
        !          9582:    the stack.  If it's a bit field, we also push offset and size info.
        !          9583: 
        !          9584:    Returns innermost component, which allows us to determine not only
        !          9585:    its type, but also whether it's a bitfield. */
        !          9586: 
        !          9587: tree
        !          9588: bc_expand_address (exp)
        !          9589:      tree exp;
        !          9590: {
        !          9591:   /* Safeguard */
        !          9592:   if (!exp || TREE_CODE (exp) == ERROR_MARK)
        !          9593:     return (exp);
        !          9594: 
        !          9595: 
        !          9596:   switch (TREE_CODE (exp))
        !          9597:     {
        !          9598:     case ARRAY_REF:
        !          9599: 
        !          9600:       return (bc_expand_address (bc_canonicalize_array_ref (exp)));
        !          9601: 
        !          9602:     case COMPONENT_REF:
        !          9603: 
        !          9604:       return (bc_expand_component_address (exp));
        !          9605: 
        !          9606:     case INDIRECT_REF:
        !          9607: 
        !          9608:       bc_expand_expr (TREE_OPERAND (exp, 0));
        !          9609: 
        !          9610:       /* For variable-sized types: retrieve pointer.  Sometimes the
        !          9611:         TYPE_SIZE tree is NULL.  Is this a bug or a feature?  Let's
        !          9612:         also make sure we have an operand, just in case... */
        !          9613: 
        !          9614:       if (TREE_OPERAND (exp, 0)
        !          9615:          && TYPE_SIZE (TREE_TYPE (TREE_OPERAND (exp, 0)))
        !          9616:          && TREE_CODE (TYPE_SIZE (TREE_TYPE (TREE_OPERAND (exp, 0)))) != INTEGER_CST)
        !          9617:        bc_emit_instruction (loadP);
        !          9618: 
        !          9619:       /* If packed, also return offset and size */
        !          9620:       if (DECL_BIT_FIELD (TREE_OPERAND (exp, 0)))
        !          9621:        
        !          9622:        bc_push_offset_and_size (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (TREE_OPERAND (exp, 0))),
        !          9623:                                 TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (exp, 0))));
        !          9624: 
        !          9625:       return (TREE_OPERAND (exp, 0));
        !          9626: 
        !          9627:     case FUNCTION_DECL:
        !          9628: 
        !          9629:       bc_load_externaddr_id (DECL_ASSEMBLER_NAME (exp),
        !          9630:                             BYTECODE_BC_LABEL (DECL_RTL (exp))->offset);
        !          9631:       break;
        !          9632: 
        !          9633:     case PARM_DECL:
        !          9634: 
        !          9635:       bc_load_parmaddr (DECL_RTL (exp));
        !          9636: 
        !          9637:       /* For variable-sized types: retrieve pointer */
        !          9638:       if (TYPE_SIZE (TREE_TYPE (exp))
        !          9639:          && TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) != INTEGER_CST)
        !          9640:        bc_emit_instruction (loadP);
        !          9641: 
        !          9642:       /* If packed, also return offset and size */
        !          9643:       if (DECL_BIT_FIELD (exp))
        !          9644:        bc_push_offset_and_size (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (exp)),
        !          9645:                                 TREE_INT_CST_LOW (DECL_SIZE (exp)));
        !          9646: 
        !          9647:       break;
        !          9648: 
        !          9649:     case RESULT_DECL:
        !          9650: 
        !          9651:       bc_emit_instruction (returnP);
        !          9652:       break;
        !          9653: 
        !          9654:     case VAR_DECL:
        !          9655: 
        !          9656: #if 0
        !          9657:       if (BYTECODE_LABEL (DECL_RTL (exp)))
        !          9658:        bc_load_externaddr (DECL_RTL (exp));
        !          9659: #endif
        !          9660: 
        !          9661:       if (DECL_EXTERNAL (exp))
        !          9662:        bc_load_externaddr_id (DECL_ASSEMBLER_NAME (exp),
        !          9663:                               (BYTECODE_BC_LABEL (DECL_RTL (exp)))->offset);
        !          9664:       else
        !          9665:        bc_load_localaddr (DECL_RTL (exp));
        !          9666: 
        !          9667:       /* For variable-sized types: retrieve pointer */
        !          9668:       if (TYPE_SIZE (TREE_TYPE (exp))
        !          9669:          && TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) != INTEGER_CST)
        !          9670:        bc_emit_instruction (loadP);
        !          9671: 
        !          9672:       /* If packed, also return offset and size */
        !          9673:       if (DECL_BIT_FIELD (exp))
        !          9674:        bc_push_offset_and_size (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (exp)),
        !          9675:                                 TREE_INT_CST_LOW (DECL_SIZE (exp)));
        !          9676:       
        !          9677:       break;
        !          9678: 
        !          9679:     case STRING_CST:
        !          9680:       {
        !          9681:        rtx r;
        !          9682:        
        !          9683:        bc_emit_bytecode (constP);
        !          9684:        r = output_constant_def (exp);
        !          9685:        bc_emit_code_labelref (BYTECODE_LABEL (r), BYTECODE_BC_LABEL (r)->offset);
        !          9686: 
        !          9687: #ifdef DEBUG_PRINT_CODE
        !          9688:        fputc ('\n', stderr);
        !          9689: #endif
        !          9690:       }
        !          9691:       break;
        !          9692: 
        !          9693:     default:
        !          9694: 
        !          9695:       abort();
        !          9696:       break;
        !          9697:     }
        !          9698: 
        !          9699:   /* Most lvalues don't have components. */
        !          9700:   return (exp);
        !          9701: }
        !          9702: 
        !          9703: 
        !          9704: /* Emit a type code to be used by the runtime support in handling
        !          9705:    parameter passing.   The type code consists of the machine mode
        !          9706:    plus the minimal alignment shifted left 8 bits.  */
        !          9707: 
        !          9708: tree
        !          9709: bc_runtime_type_code (type)
        !          9710:      tree type;
        !          9711: {
        !          9712:   int val;
        !          9713: 
        !          9714:   switch (TREE_CODE (type))
        !          9715:     {
        !          9716:     case VOID_TYPE:
        !          9717:     case INTEGER_TYPE:
        !          9718:     case REAL_TYPE:
        !          9719:     case COMPLEX_TYPE:
        !          9720:     case ENUMERAL_TYPE:
        !          9721:     case POINTER_TYPE:
        !          9722:     case RECORD_TYPE:
        !          9723: 
        !          9724:       val = (int) TYPE_MODE (type) | TYPE_ALIGN (type) << 8;
        !          9725:       break;
        !          9726: 
        !          9727:     case ERROR_MARK:
        !          9728: 
        !          9729:       val = 0;
        !          9730:       break;
        !          9731: 
        !          9732:     default:
        !          9733: 
        !          9734:       abort ();
        !          9735:     }
        !          9736:   return build_int_2 (val, 0);
        !          9737: }
        !          9738: 
        !          9739: 
        !          9740: /* Generate constructor label */
        !          9741: char *
        !          9742: bc_gen_constr_label ()
        !          9743: {
        !          9744:   static int label_counter;
        !          9745:   static char label[20];
        !          9746: 
        !          9747:   sprintf (label, "*LR%d", label_counter++);
        !          9748: 
        !          9749:   return (obstack_copy0 (&permanent_obstack, label, strlen (label)));
        !          9750: }
        !          9751: 
        !          9752: 
        !          9753: /* Evaluate constructor CONSTR and return pointer to it on level one.  We
        !          9754:    expand the constructor data as static data, and push a pointer to it.
        !          9755:    The pointer is put in the pointer table and is retrieved by a constP
        !          9756:    bytecode instruction.  We then loop and store each constructor member in
        !          9757:    the corresponding component.  Finally, we return the original pointer on
        !          9758:    the stack. */
        !          9759: 
        !          9760: void
        !          9761: bc_expand_constructor (constr)
        !          9762:      tree constr;
        !          9763: {
        !          9764:   char *l;
        !          9765:   HOST_WIDE_INT ptroffs;
        !          9766:   rtx constr_rtx;
        !          9767: 
        !          9768:   
        !          9769:   /* Literal constructors are handled as constants, whereas
        !          9770:      non-literals are evaluated and stored element by element
        !          9771:      into the data segment. */
        !          9772:   
        !          9773:   /* Allocate space in proper segment and push pointer to space on stack.
        !          9774:    */
        !          9775: 
        !          9776:   l = bc_gen_constr_label ();
        !          9777: 
        !          9778:   if (TREE_CONSTANT (constr))
        !          9779:     {
        !          9780:       text_section ();
        !          9781: 
        !          9782:       bc_emit_const_labeldef (l);
        !          9783:       bc_output_constructor (constr, int_size_in_bytes (TREE_TYPE (constr)));
        !          9784:     }
        !          9785:   else
        !          9786:     {
        !          9787:       data_section ();
        !          9788: 
        !          9789:       bc_emit_data_labeldef (l);
        !          9790:       bc_output_data_constructor (constr);
        !          9791:     }
        !          9792: 
        !          9793:   
        !          9794:   /* Add reference to pointer table and recall pointer to stack;
        !          9795:      this code is common for both types of constructors: literals
        !          9796:      and non-literals. */
        !          9797: 
        !          9798:   ptroffs = bc_define_pointer (l);
        !          9799:   bc_emit_instruction (constP, ptroffs);
        !          9800: 
        !          9801:   /* This is all that has to be done if it's a literal. */
        !          9802:   if (TREE_CONSTANT (constr))
        !          9803:     return;
        !          9804: 
        !          9805: 
        !          9806:   /* At this point, we have the pointer to the structure on top of the stack.
        !          9807:      Generate sequences of store_memory calls for the constructor. */
        !          9808:   
        !          9809:   /* constructor type is structure */
        !          9810:   if (TREE_CODE (TREE_TYPE (constr)) == RECORD_TYPE)
        !          9811:     {
        !          9812:       register tree elt;
        !          9813:       
        !          9814:       /* If the constructor has fewer fields than the structure,
        !          9815:         clear the whole structure first.  */
        !          9816:       
        !          9817:       if (list_length (CONSTRUCTOR_ELTS (constr))
        !          9818:          != list_length (TYPE_FIELDS (TREE_TYPE (constr))))
        !          9819:        {
        !          9820:          bc_emit_instruction (duplicate);
        !          9821:          bc_emit_instruction (constSI, (HOST_WIDE_INT) int_size_in_bytes (TREE_TYPE (constr)));
        !          9822:          bc_emit_instruction (clearBLK);
        !          9823:        }
        !          9824:       
        !          9825:       /* Store each element of the constructor into the corresponding
        !          9826:         field of TARGET.  */
        !          9827:       
        !          9828:       for (elt = CONSTRUCTOR_ELTS (constr); elt; elt = TREE_CHAIN (elt))
        !          9829:        {
        !          9830:          register tree field = TREE_PURPOSE (elt);
        !          9831:          register enum machine_mode mode;
        !          9832:          int bitsize;
        !          9833:          int bitpos;
        !          9834:          int unsignedp;
        !          9835:          
        !          9836:          bitsize = TREE_INT_CST_LOW (DECL_SIZE (field)) /* * DECL_SIZE_UNIT (field) */;
        !          9837:          mode = DECL_MODE (field);
        !          9838:          unsignedp = TREE_UNSIGNED (field);
        !          9839: 
        !          9840:          bitpos = TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field));
        !          9841:          
        !          9842:          bc_store_field (elt, bitsize, bitpos, mode, TREE_VALUE (elt), TREE_TYPE (TREE_VALUE (elt)),
        !          9843:                          /* The alignment of TARGET is
        !          9844:                             at least what its type requires.  */
        !          9845:                          VOIDmode, 0,
        !          9846:                          TYPE_ALIGN (TREE_TYPE (constr)) / BITS_PER_UNIT,
        !          9847:                          int_size_in_bytes (TREE_TYPE (constr)));
        !          9848:        }
        !          9849:     }
        !          9850:   else
        !          9851:     
        !          9852:     /* Constructor type is array */
        !          9853:     if (TREE_CODE (TREE_TYPE (constr)) == ARRAY_TYPE)
        !          9854:       {
        !          9855:        register tree elt;
        !          9856:        register int i;
        !          9857:        tree domain = TYPE_DOMAIN (TREE_TYPE (constr));
        !          9858:        int minelt = TREE_INT_CST_LOW (TYPE_MIN_VALUE (domain));
        !          9859:        int maxelt = TREE_INT_CST_LOW (TYPE_MAX_VALUE (domain));
        !          9860:        tree elttype = TREE_TYPE (TREE_TYPE (constr));
        !          9861:        
        !          9862:        /* If the constructor has fewer fields than the structure,
        !          9863:           clear the whole structure first.  */
        !          9864:        
        !          9865:        if (list_length (CONSTRUCTOR_ELTS (constr)) < maxelt - minelt + 1)
        !          9866:          {
        !          9867:            bc_emit_instruction (duplicate);
        !          9868:            bc_emit_instruction (constSI, (HOST_WIDE_INT) int_size_in_bytes (TREE_TYPE (constr)));
        !          9869:            bc_emit_instruction (clearBLK);
        !          9870:          }
        !          9871:        
        !          9872:        
        !          9873:        /* Store each element of the constructor into the corresponding
        !          9874:           element of TARGET, determined by counting the elements. */
        !          9875:        
        !          9876:        for (elt = CONSTRUCTOR_ELTS (constr), i = 0;
        !          9877:             elt;
        !          9878:             elt = TREE_CHAIN (elt), i++)
        !          9879:          {
        !          9880:            register enum machine_mode mode;
        !          9881:            int bitsize;
        !          9882:            int bitpos;
        !          9883:            int unsignedp;
        !          9884:            
        !          9885:            mode = TYPE_MODE (elttype);
        !          9886:            bitsize = GET_MODE_BITSIZE (mode);
        !          9887:            unsignedp = TREE_UNSIGNED (elttype);
        !          9888:            
        !          9889:            bitpos = (i * TREE_INT_CST_LOW (TYPE_SIZE (elttype))
        !          9890:                      /* * TYPE_SIZE_UNIT (elttype) */ );
        !          9891:            
        !          9892:            bc_store_field (elt, bitsize, bitpos, mode,
        !          9893:                            TREE_VALUE (elt), TREE_TYPE (TREE_VALUE (elt)),
        !          9894:                            /* The alignment of TARGET is
        !          9895:                               at least what its type requires.  */
        !          9896:                            VOIDmode, 0,
        !          9897:                            TYPE_ALIGN (TREE_TYPE (constr)) / BITS_PER_UNIT,
        !          9898:                            int_size_in_bytes (TREE_TYPE (constr)));
        !          9899:          }
        !          9900:   
        !          9901:       }
        !          9902: }
        !          9903: 
        !          9904: 
        !          9905: /* Store the value of EXP (an expression tree) into member FIELD of
        !          9906:    structure at address on stack, which has type TYPE, mode MODE and
        !          9907:    occupies BITSIZE bits, starting BITPOS bits from the beginning of the
        !          9908:    structure.
        !          9909: 
        !          9910:    ALIGN is the alignment that TARGET is known to have, measured in bytes.
        !          9911:    TOTAL_SIZE is its size in bytes, or -1 if variable.  */
        !          9912: 
        !          9913: void
        !          9914: bc_store_field (field, bitsize, bitpos, mode, exp, type,
        !          9915:                value_mode, unsignedp, align, total_size)
        !          9916:      int bitsize, bitpos;
        !          9917:      enum machine_mode mode;
        !          9918:      tree field, exp, type;
        !          9919:      enum machine_mode value_mode;
        !          9920:      int unsignedp;
        !          9921:      int align;
        !          9922:      int total_size;
        !          9923: {
        !          9924: 
        !          9925:   /* Expand expression and copy pointer */
        !          9926:   bc_expand_expr (exp);
        !          9927:   bc_emit_instruction (over);
        !          9928: 
        !          9929: 
        !          9930:   /* If the component is a bit field, we cannot use addressing to access
        !          9931:      it.  Use bit-field techniques to store in it.  */
        !          9932: 
        !          9933:   if (DECL_BIT_FIELD (field))
        !          9934:     {
        !          9935:       bc_store_bit_field (bitpos, bitsize, unsignedp);
        !          9936:       return;
        !          9937:     }
        !          9938:   else
        !          9939:     /* Not bit field */
        !          9940:     {
        !          9941:       HOST_WIDE_INT offset = bitpos / BITS_PER_UNIT;
        !          9942: 
        !          9943:       /* Advance pointer to the desired member */
        !          9944:       if (offset)
        !          9945:        bc_emit_instruction (addconstPSI, offset);
        !          9946: 
        !          9947:       /* Store */
        !          9948:       bc_store_memory (type, field);
        !          9949:     }
        !          9950: }
        !          9951: 
        !          9952: 
        !          9953: /* Store SI/SU in bitfield */
        !          9954: void
        !          9955: bc_store_bit_field (offset, size, unsignedp)
        !          9956:      int offset, size, unsignedp;
        !          9957: {
        !          9958:   /* Push bitfield offset and size */
        !          9959:   bc_push_offset_and_size (offset, size);
        !          9960: 
        !          9961:   /* Store */
        !          9962:   bc_emit_instruction (sstoreBI);
        !          9963: }
        !          9964: 
        !          9965: 
        !          9966: /* Load SI/SU from bitfield */
        !          9967: void
        !          9968: bc_load_bit_field (offset, size, unsignedp)
        !          9969:      int offset, size, unsignedp;
        !          9970: {
        !          9971:   /* Push bitfield offset and size */
        !          9972:   bc_push_offset_and_size (offset, size);
        !          9973: 
        !          9974:   /* Load: sign-extend if signed, else zero-extend */
        !          9975:   bc_emit_instruction (unsignedp ? zxloadBI : sxloadBI);
        !          9976: }  
        !          9977: 
        !          9978: 
        !          9979: /* Adjust interpreter stack by NLEVELS.  Positive means drop NLEVELS
        !          9980:    (adjust stack pointer upwards), negative means add that number of
        !          9981:    levels (adjust the stack pointer downwards).  Only positive values
        !          9982:    normally make sense. */
        !          9983: 
        !          9984: void
        !          9985: bc_adjust_stack (nlevels)
        !          9986:      int nlevels;
        !          9987: {
        !          9988:   switch (nlevels)
        !          9989:     {
        !          9990:     case 0:
        !          9991:       break;
        !          9992:       
        !          9993:     case 2:
        !          9994:       bc_emit_instruction (drop);
        !          9995:       
        !          9996:     case 1:
        !          9997:       bc_emit_instruction (drop);
        !          9998:       break;
        !          9999:       
        !          10000:     default:
        !          10001:       
        !          10002:       bc_emit_instruction (adjstackSI, (HOST_WIDE_INT) nlevels);
        !          10003:       stack_depth -= nlevels;
        !          10004:     }
        !          10005: 
        !          10006: #if defined (VALIDATE_STACK_FOR_BC)
        !          10007:   VALIDATE_STACK_FOR_BC ();
        !          10008: #endif
        !          10009: }

unix.superglobalmegacorp.com

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