Annotation of gcc/expr.c, revision 1.1.1.5

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

unix.superglobalmegacorp.com

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