Annotation of gcc/expr.c, revision 1.1

1.1     ! root        1: /* Convert tree expression to rtl instructions, for GNU compiler.
        !             2:    Copyright (C) 1988, 1992 Free Software Foundation, Inc.
        !             3: 
        !             4: This file is part of GNU CC.
        !             5: 
        !             6: GNU CC is free software; you can redistribute it and/or modify
        !             7: it under the terms of the GNU General Public License as published by
        !             8: the Free Software Foundation; either version 2, or (at your option)
        !             9: any later version.
        !            10: 
        !            11: GNU CC is distributed in the hope that it will be useful,
        !            12: but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            14: GNU General Public License for more details.
        !            15: 
        !            16: You should have received a copy of the GNU General Public License
        !            17: along with GNU CC; see the file COPYING.  If not, write to
        !            18: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
        !            19: 
        !            20: 
        !            21: #include "config.h"
        !            22: #include "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 "gvarargs.h"
        !            33: #include "typeclass.h"
        !            34: 
        !            35: #define CEIL(x,y) (((x) + (y) - 1) / (y))
        !            36: 
        !            37: /* Decide whether a function's arguments should be processed
        !            38:    from first to last or from last to first.  */
        !            39: 
        !            40: #ifdef STACK_GROWS_DOWNWARD
        !            41: #ifdef PUSH_ROUNDING
        !            42: #define PUSH_ARGS_REVERSED     /* If it's last to first */
        !            43: #endif
        !            44: #endif
        !            45: 
        !            46: #ifndef STACK_PUSH_CODE
        !            47: #ifdef STACK_GROWS_DOWNWARD
        !            48: #define STACK_PUSH_CODE PRE_DEC
        !            49: #else
        !            50: #define STACK_PUSH_CODE PRE_INC
        !            51: #endif
        !            52: #endif
        !            53: 
        !            54: /* Like STACK_BOUNDARY but in units of bytes, not bits.  */
        !            55: #define STACK_BYTES (STACK_BOUNDARY / BITS_PER_UNIT)
        !            56: 
        !            57: /* If this is nonzero, we do not bother generating VOLATILE
        !            58:    around volatile memory references, and we are willing to
        !            59:    output indirect addresses.  If cse is to follow, we reject
        !            60:    indirect addresses so a useful potential cse is generated;
        !            61:    if it is used only once, instruction combination will produce
        !            62:    the same indirect address eventually.  */
        !            63: int cse_not_expected;
        !            64: 
        !            65: /* Nonzero to generate code for all the subroutines within an
        !            66:    expression before generating the upper levels of the expression.
        !            67:    Nowadays this is never zero.  */
        !            68: int do_preexpand_calls = 1;
        !            69: 
        !            70: /* Number of units that we should eventually pop off the stack.
        !            71:    These are the arguments to function calls that have already returned.  */
        !            72: int pending_stack_adjust;
        !            73: 
        !            74: /* Nonzero means stack pops must not be deferred, and deferred stack
        !            75:    pops must not be output.  It is nonzero inside a function call,
        !            76:    inside a conditional expression, inside a statement expression,
        !            77:    and in other cases as well.  */
        !            78: int inhibit_defer_pop;
        !            79: 
        !            80: /* A list of all cleanups which belong to the arguments of
        !            81:    function calls being expanded by expand_call.  */
        !            82: tree cleanups_this_call;
        !            83: 
        !            84: /* Nonzero means __builtin_saveregs has already been done in this function.
        !            85:    The value is the pseudoreg containing the value __builtin_saveregs
        !            86:    returned.  */
        !            87: static rtx saveregs_value;
        !            88: 
        !            89: rtx store_expr ();
        !            90: static void store_constructor ();
        !            91: static rtx store_field ();
        !            92: static rtx expand_builtin ();
        !            93: static rtx compare ();
        !            94: static rtx do_store_flag ();
        !            95: static void preexpand_calls ();
        !            96: static rtx expand_increment ();
        !            97: static void init_queue ();
        !            98: 
        !            99: void do_pending_stack_adjust ();
        !           100: static void do_jump_for_compare ();
        !           101: static void do_jump_by_parts_equality ();
        !           102: static void do_jump_by_parts_equality_rtx ();
        !           103: static void do_jump_by_parts_greater ();
        !           104: 
        !           105: /* MOVE_RATIO is the number of move instructions that is better than
        !           106:    a block move.  */
        !           107: 
        !           108: #ifndef MOVE_RATIO
        !           109: #if defined (HAVE_movstrqi) || defined (HAVE_movstrhi) || defined (HAVE_movstrsi) || defined (HAVE_movstrdi)
        !           110: #define MOVE_RATIO 2
        !           111: #else
        !           112: /* A value of around 6 would minimize code size; infinity would minimize
        !           113:    execution time.  */
        !           114: #define MOVE_RATIO 15
        !           115: #endif
        !           116: #endif
        !           117: 
        !           118: /* This is run at the start of compiling a function.  */
        !           119: 
        !           120: void
        !           121: init_expr ()
        !           122: {
        !           123:   init_queue ();
        !           124: 
        !           125:   pending_stack_adjust = 0;
        !           126:   inhibit_defer_pop = 0;
        !           127:   cleanups_this_call = 0;
        !           128:   saveregs_value = 0;
        !           129: }
        !           130: 
        !           131: /* Save all variables describing the current status into the structure *P.
        !           132:    This is used before starting a nested function.  */
        !           133: 
        !           134: void
        !           135: save_expr_status (p)
        !           136:      struct function *p;
        !           137: {
        !           138:   /* Instead of saving the postincrement queue, empty it.  */
        !           139:   emit_queue ();
        !           140: 
        !           141:   p->pending_stack_adjust = pending_stack_adjust;
        !           142:   p->inhibit_defer_pop = inhibit_defer_pop;
        !           143:   p->cleanups_this_call = cleanups_this_call;
        !           144:   p->saveregs_value = saveregs_value;
        !           145: 
        !           146:   pending_stack_adjust = 0;
        !           147:   inhibit_defer_pop = 0;
        !           148:   cleanups_this_call = 0;
        !           149:   saveregs_value = 0;
        !           150: }
        !           151: 
        !           152: /* Restore all variables describing the current status from the structure *P.
        !           153:    This is used after a nested function.  */
        !           154: 
        !           155: void
        !           156: restore_expr_status (p)
        !           157:      struct function *p;
        !           158: {
        !           159:   pending_stack_adjust = p->pending_stack_adjust;
        !           160:   inhibit_defer_pop = p->inhibit_defer_pop;
        !           161:   cleanups_this_call = p->cleanups_this_call;
        !           162:   saveregs_value = p->saveregs_value;
        !           163: }
        !           164: 
        !           165: /* Manage the queue of increment instructions to be output
        !           166:    for POSTINCREMENT_EXPR expressions, etc.  */
        !           167: 
        !           168: static rtx pending_chain;
        !           169: 
        !           170: /* Queue up to increment (or change) VAR later.  BODY says how:
        !           171:    BODY should be the same thing you would pass to emit_insn
        !           172:    to increment right away.  It will go to emit_insn later on.
        !           173: 
        !           174:    The value is a QUEUED expression to be used in place of VAR
        !           175:    where you want to guarantee the pre-incrementation value of VAR.  */
        !           176: 
        !           177: static rtx
        !           178: enqueue_insn (var, body)
        !           179:      rtx var, body;
        !           180: {
        !           181:   pending_chain = gen_rtx (QUEUED, GET_MODE (var),
        !           182:                           var, 0, 0, body, pending_chain);
        !           183:   return pending_chain;
        !           184: }
        !           185: 
        !           186: /* Use protect_from_queue to convert a QUEUED expression
        !           187:    into something that you can put immediately into an instruction.
        !           188:    If the queued incrementation has not happened yet,
        !           189:    protect_from_queue returns the variable itself.
        !           190:    If the incrementation has happened, protect_from_queue returns a temp
        !           191:    that contains a copy of the old value of the variable.
        !           192: 
        !           193:    Any time an rtx which might possibly be a QUEUED is to be put
        !           194:    into an instruction, it must be passed through protect_from_queue first.
        !           195:    QUEUED expressions are not meaningful in instructions.
        !           196: 
        !           197:    Do not pass a value through protect_from_queue and then hold
        !           198:    on to it for a while before putting it in an instruction!
        !           199:    If the queue is flushed in between, incorrect code will result.  */
        !           200: 
        !           201: rtx
        !           202: protect_from_queue (x, modify)
        !           203:      register rtx x;
        !           204:      int modify;
        !           205: {
        !           206:   register RTX_CODE code = GET_CODE (x);
        !           207: 
        !           208: #if 0  /* A QUEUED can hang around after the queue is forced out.  */
        !           209:   /* Shortcut for most common case.  */
        !           210:   if (pending_chain == 0)
        !           211:     return x;
        !           212: #endif
        !           213: 
        !           214:   if (code != QUEUED)
        !           215:     {
        !           216:       /* A special hack for read access to (MEM (QUEUED ...))
        !           217:         to facilitate use of autoincrement.
        !           218:         Make a copy of the contents of the memory location
        !           219:         rather than a copy of the address, but not
        !           220:         if the value is of mode BLKmode.  */
        !           221:       if (code == MEM && GET_MODE (x) != BLKmode
        !           222:          && GET_CODE (XEXP (x, 0)) == QUEUED && !modify)
        !           223:        {
        !           224:          register rtx y = XEXP (x, 0);
        !           225:          XEXP (x, 0) = QUEUED_VAR (y);
        !           226:          if (QUEUED_INSN (y))
        !           227:            {
        !           228:              register rtx temp = gen_reg_rtx (GET_MODE (x));
        !           229:              emit_insn_before (gen_move_insn (temp, x),
        !           230:                                QUEUED_INSN (y));
        !           231:              return temp;
        !           232:            }
        !           233:          return x;
        !           234:        }
        !           235:       /* Otherwise, recursively protect the subexpressions of all
        !           236:         the kinds of rtx's that can contain a QUEUED.  */
        !           237:       if (code == MEM)
        !           238:        XEXP (x, 0) = protect_from_queue (XEXP (x, 0), 0);
        !           239:       else if (code == PLUS || code == MULT)
        !           240:        {
        !           241:          XEXP (x, 0) = protect_from_queue (XEXP (x, 0), 0);
        !           242:          XEXP (x, 1) = protect_from_queue (XEXP (x, 1), 0);
        !           243:        }
        !           244:       return x;
        !           245:     }
        !           246:   /* If the increment has not happened, use the variable itself.  */
        !           247:   if (QUEUED_INSN (x) == 0)
        !           248:     return QUEUED_VAR (x);
        !           249:   /* If the increment has happened and a pre-increment copy exists,
        !           250:      use that copy.  */
        !           251:   if (QUEUED_COPY (x) != 0)
        !           252:     return QUEUED_COPY (x);
        !           253:   /* The increment has happened but we haven't set up a pre-increment copy.
        !           254:      Set one up now, and use it.  */
        !           255:   QUEUED_COPY (x) = gen_reg_rtx (GET_MODE (QUEUED_VAR (x)));
        !           256:   emit_insn_before (gen_move_insn (QUEUED_COPY (x), QUEUED_VAR (x)),
        !           257:                    QUEUED_INSN (x));
        !           258:   return QUEUED_COPY (x);
        !           259: }
        !           260: 
        !           261: /* Return nonzero if X contains a QUEUED expression:
        !           262:    if it contains anything that will be altered by a queued increment.
        !           263:    We handle only combinations of MEM, PLUS, MINUS and MULT operators
        !           264:    since memory addresses generally contain only those.  */
        !           265: 
        !           266: static int
        !           267: queued_subexp_p (x)
        !           268:      rtx x;
        !           269: {
        !           270:   register enum rtx_code code = GET_CODE (x);
        !           271:   switch (code)
        !           272:     {
        !           273:     case QUEUED:
        !           274:       return 1;
        !           275:     case MEM:
        !           276:       return queued_subexp_p (XEXP (x, 0));
        !           277:     case MULT:
        !           278:     case PLUS:
        !           279:     case MINUS:
        !           280:       return queued_subexp_p (XEXP (x, 0))
        !           281:        || queued_subexp_p (XEXP (x, 1));
        !           282:     }
        !           283:   return 0;
        !           284: }
        !           285: 
        !           286: /* Perform all the pending incrementations.  */
        !           287: 
        !           288: void
        !           289: emit_queue ()
        !           290: {
        !           291:   register rtx p;
        !           292:   while (p = pending_chain)
        !           293:     {
        !           294:       QUEUED_INSN (p) = emit_insn (QUEUED_BODY (p));
        !           295:       pending_chain = QUEUED_NEXT (p);
        !           296:     }
        !           297: }
        !           298: 
        !           299: static void
        !           300: init_queue ()
        !           301: {
        !           302:   if (pending_chain)
        !           303:     abort ();
        !           304: }
        !           305: 
        !           306: /* Copy data from FROM to TO, where the machine modes are not the same.
        !           307:    Both modes may be integer, or both may be floating.
        !           308:    UNSIGNEDP should be nonzero if FROM is an unsigned type.
        !           309:    This causes zero-extension instead of sign-extension.  */
        !           310: 
        !           311: void
        !           312: convert_move (to, from, unsignedp)
        !           313:      register rtx to, from;
        !           314:      int unsignedp;
        !           315: {
        !           316:   enum machine_mode to_mode = GET_MODE (to);
        !           317:   enum machine_mode from_mode = GET_MODE (from);
        !           318:   int to_real = GET_MODE_CLASS (to_mode) == MODE_FLOAT;
        !           319:   int from_real = GET_MODE_CLASS (from_mode) == MODE_FLOAT;
        !           320:   enum insn_code code;
        !           321:   rtx libcall;
        !           322: 
        !           323:   /* rtx code for making an equivalent value.  */
        !           324:   enum rtx_code equiv_code = (unsignedp ? ZERO_EXTEND : SIGN_EXTEND);
        !           325: 
        !           326:   to = protect_from_queue (to, 1);
        !           327:   from = protect_from_queue (from, 0);
        !           328: 
        !           329:   if (to_real != from_real)
        !           330:     abort ();
        !           331: 
        !           332:   if (to_mode == from_mode
        !           333:       || (from_mode == VOIDmode && CONSTANT_P (from)))
        !           334:     {
        !           335:       emit_move_insn (to, from);
        !           336:       return;
        !           337:     }
        !           338: 
        !           339:   if (to_real)
        !           340:     {
        !           341: #ifdef HAVE_extendsfdf2
        !           342:       if (HAVE_extendsfdf2 && from_mode == SFmode && to_mode == DFmode)
        !           343:        {
        !           344:          emit_unop_insn (CODE_FOR_extendsfdf2, to, from, UNKNOWN);
        !           345:          return;
        !           346:        }
        !           347: #endif
        !           348: #ifdef HAVE_extendsftf2
        !           349:       if (HAVE_extendsftf2 && from_mode == SFmode && to_mode == TFmode)
        !           350:        {
        !           351:          emit_unop_insn (CODE_FOR_extendsftf2, to, from, UNKNOWN);
        !           352:          return;
        !           353:        }
        !           354: #endif
        !           355: #ifdef HAVE_extenddftf2
        !           356:       if (HAVE_extenddftf2 && from_mode == DFmode && to_mode == TFmode)
        !           357:        {
        !           358:          emit_unop_insn (CODE_FOR_extenddftf2, to, from, UNKNOWN);
        !           359:          return;
        !           360:        }
        !           361: #endif
        !           362: #ifdef HAVE_truncdfsf2
        !           363:       if (HAVE_truncdfsf2 && from_mode == DFmode && to_mode == SFmode)
        !           364:        {
        !           365:          emit_unop_insn (CODE_FOR_truncdfsf2, to, from, UNKNOWN);
        !           366:          return;
        !           367:        }
        !           368: #endif
        !           369: #ifdef HAVE_trunctfsf2
        !           370:       if (HAVE_trunctfsf2 && from_mode == TFmode && to_mode == SFmode)
        !           371:        {
        !           372:          emit_unop_insn (CODE_FOR_trunctfsf2, to, from, UNKNOWN);
        !           373:          return;
        !           374:        }
        !           375: #endif
        !           376: #ifdef HAVE_trunctfdf2
        !           377:       if (HAVE_trunctfdf2 && from_mode == TFmode && to_mode == DFmode)
        !           378:        {
        !           379:          emit_unop_insn (CODE_FOR_trunctfdf2, to, from, UNKNOWN);
        !           380:          return;
        !           381:        }
        !           382: #endif
        !           383: 
        !           384:       if (from_mode == SFmode && to_mode == DFmode)
        !           385:        libcall = extendsfdf2_libfunc;
        !           386:       else if (from_mode == DFmode && to_mode == SFmode)
        !           387:        libcall = truncdfsf2_libfunc;
        !           388:       else
        !           389:        /* This conversion is not implemented yet.  There aren't any TFmode
        !           390:           library calls.  */
        !           391:        abort ();
        !           392: 
        !           393:       emit_library_call (libcall, 0, to_mode, 1, from, from_mode);
        !           394:       emit_move_insn (to, hard_libcall_value (to_mode));
        !           395:       return;
        !           396:     }
        !           397: 
        !           398:   /* Now both modes are integers.  */
        !           399: 
        !           400:   /* Handle expanding beyond a word.  */
        !           401:   if (GET_MODE_BITSIZE (from_mode) < GET_MODE_BITSIZE (to_mode)
        !           402:       && GET_MODE_BITSIZE (to_mode) > BITS_PER_WORD)
        !           403:     {
        !           404:       rtx insns;
        !           405:       rtx lowpart;
        !           406:       rtx fill_value;
        !           407:       rtx lowfrom;
        !           408:       int i;
        !           409:       enum machine_mode lowpart_mode;
        !           410:       int nwords = CEIL (GET_MODE_SIZE (to_mode), UNITS_PER_WORD);
        !           411: 
        !           412:       /* Try converting directly if the insn is supported.  */
        !           413:       if ((code = can_extend_p (to_mode, from_mode, unsignedp))
        !           414:          != CODE_FOR_nothing)
        !           415:        {
        !           416:          emit_unop_insn (code, to, from, equiv_code);
        !           417:          return;
        !           418:        }
        !           419:       /* Next, try converting via full word.  */
        !           420:       else if (GET_MODE_BITSIZE (from_mode) < BITS_PER_WORD
        !           421:               && ((code = can_extend_p (to_mode, word_mode, unsignedp))
        !           422:                   != CODE_FOR_nothing))
        !           423:        {
        !           424:          convert_move (gen_lowpart (word_mode, to), from, unsignedp);
        !           425:          emit_unop_insn (code, to,
        !           426:                          gen_lowpart (word_mode, to), equiv_code);
        !           427:          return;
        !           428:        }
        !           429: 
        !           430:       /* No special multiword conversion insn; do it by hand.  */
        !           431:       start_sequence ();
        !           432: 
        !           433:       /* Get a copy of FROM widened to a word, if necessary.  */
        !           434:       if (GET_MODE_BITSIZE (from_mode) < BITS_PER_WORD)
        !           435:        lowpart_mode = word_mode;
        !           436:       else
        !           437:        lowpart_mode = from_mode;
        !           438: 
        !           439:       lowfrom = convert_to_mode (lowpart_mode, from, unsignedp);
        !           440: 
        !           441:       lowpart = gen_lowpart (lowpart_mode, to);
        !           442:       emit_move_insn (lowpart, lowfrom);
        !           443: 
        !           444:       /* Compute the value to put in each remaining word.  */
        !           445:       if (unsignedp)
        !           446:        fill_value = const0_rtx;
        !           447:       else
        !           448:        {
        !           449: #ifdef HAVE_slt
        !           450:          if (HAVE_slt
        !           451:              && insn_operand_mode[(int) CODE_FOR_slt][0] == word_mode
        !           452:              && STORE_FLAG_VALUE == -1)
        !           453:            {
        !           454:              emit_cmp_insn (lowfrom, const0_rtx, NE, 0, lowpart_mode, 0, 0);
        !           455:              fill_value = gen_reg_rtx (word_mode);
        !           456:              emit_insn (gen_slt (fill_value));
        !           457:            }
        !           458:          else
        !           459: #endif
        !           460:            {
        !           461:              fill_value
        !           462:                = expand_shift (RSHIFT_EXPR, lowpart_mode, lowfrom,
        !           463:                                size_int (GET_MODE_BITSIZE (lowpart_mode) - 1),
        !           464:                                0, 0);
        !           465:              fill_value = convert_to_mode (word_mode, fill_value, 1);
        !           466:            }
        !           467:        }
        !           468: 
        !           469:       /* Fill the remaining words.  */
        !           470:       for (i = GET_MODE_SIZE (lowpart_mode) / UNITS_PER_WORD; i < nwords; i++)
        !           471:        {
        !           472:          int index = (WORDS_BIG_ENDIAN ? nwords - i - 1 : i);
        !           473:          rtx subword = operand_subword (to, index, 1, to_mode);
        !           474: 
        !           475:          if (subword == 0)
        !           476:            abort ();
        !           477: 
        !           478:          if (fill_value != subword)
        !           479:            emit_move_insn (subword, fill_value);
        !           480:        }
        !           481: 
        !           482:       insns = get_insns ();
        !           483:       end_sequence ();
        !           484: 
        !           485:       emit_no_conflict_block (insns, to, from, 0,
        !           486:                              gen_rtx (equiv_code, to_mode, from));
        !           487:       return;
        !           488:     }
        !           489: 
        !           490:   if (GET_MODE_BITSIZE (from_mode) > BITS_PER_WORD)
        !           491:     {
        !           492:       convert_move (to, gen_lowpart (word_mode, from), 0);
        !           493:       return;
        !           494:     }
        !           495: 
        !           496:   /* Handle pointer conversion */                      /* SPEE 900220 */
        !           497:   if (to_mode == PSImode)
        !           498:     {
        !           499:       if (from_mode != SImode)
        !           500:        from = convert_to_mode (SImode, from, unsignedp);
        !           501: 
        !           502: #ifdef HAVE_truncsipsi
        !           503:       if (HAVE_truncsipsi)
        !           504:        {
        !           505:          emit_unop_insn (CODE_FOR_truncsipsi, to, from, UNKNOWN);
        !           506:          return;
        !           507:        }
        !           508: #endif /* HAVE_truncsipsi */
        !           509:       abort ();
        !           510:     }
        !           511: 
        !           512:   if (from_mode == PSImode)
        !           513:     {
        !           514:       if (to_mode != SImode)
        !           515:        {
        !           516:          from = convert_to_mode (SImode, from, unsignedp);
        !           517:          from_mode = SImode;
        !           518:        }
        !           519:       else
        !           520:        {
        !           521: #ifdef HAVE_extendpsisi
        !           522:          if (HAVE_extendpsisi)
        !           523:            {
        !           524:              emit_unop_insn (CODE_FOR_extendpsisi, to, from, UNKNOWN);
        !           525:              return;
        !           526:            }
        !           527: #endif /* HAVE_extendpsisi */
        !           528:          abort ();
        !           529:        }
        !           530:     }
        !           531: 
        !           532:   /* Now follow all the conversions between integers
        !           533:      no more than a word long.  */
        !           534: 
        !           535:   /* For truncation, usually we can just refer to FROM in a narrower mode.  */
        !           536:   if (GET_MODE_BITSIZE (to_mode) < GET_MODE_BITSIZE (from_mode)
        !           537:       && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (to_mode),
        !           538:                                GET_MODE_BITSIZE (from_mode))
        !           539:       && ((GET_CODE (from) == MEM
        !           540:           && ! MEM_VOLATILE_P (from)
        !           541:           && ! mode_dependent_address_p (XEXP (from, 0)))
        !           542:          || GET_CODE (from) == REG
        !           543:          || GET_CODE (from) == SUBREG))
        !           544:     {
        !           545:       emit_move_insn (to, gen_lowpart (to_mode, from));
        !           546:       return;
        !           547:     }
        !           548: 
        !           549:   /* For truncation, usually we can just refer to FROM in a narrower mode.  */
        !           550:   if (GET_MODE_BITSIZE (to_mode) > GET_MODE_BITSIZE (from_mode))
        !           551:     {
        !           552:       /* Convert directly if that works.  */
        !           553:       if ((code = can_extend_p (to_mode, from_mode, unsignedp))
        !           554:          != CODE_FOR_nothing)
        !           555:        {
        !           556:          emit_unop_insn (code, to, from, equiv_code);
        !           557:          return;
        !           558:        }
        !           559:       else
        !           560:        {
        !           561:          enum machine_mode intermediate;
        !           562: 
        !           563:          /* Search for a mode to convert via.  */
        !           564:          for (intermediate = from_mode; intermediate != VOIDmode;
        !           565:               intermediate = GET_MODE_WIDER_MODE (intermediate))
        !           566:            if ((can_extend_p (to_mode, intermediate, unsignedp)
        !           567:                 != CODE_FOR_nothing)
        !           568:                && (can_extend_p (intermediate, from_mode, unsignedp)
        !           569:                    != CODE_FOR_nothing))
        !           570:              {
        !           571:                convert_move (to, convert_to_mode (intermediate, from,
        !           572:                                                   unsignedp), unsignedp);
        !           573:                return;
        !           574:              }
        !           575: 
        !           576:          /* No suitable intermediate mode.  */
        !           577:          abort ();
        !           578:        }
        !           579:     }
        !           580: 
        !           581:   /* Support special truncate insns for certain modes.  */ 
        !           582: 
        !           583:   if (from_mode == DImode && to_mode == SImode)
        !           584:     {
        !           585: #ifdef HAVE_truncdisi2
        !           586:       if (HAVE_truncdisi2)
        !           587:        {
        !           588:          emit_unop_insn (CODE_FOR_truncdisi2, to, from, UNKNOWN);
        !           589:          return;
        !           590:        }
        !           591: #endif
        !           592:       convert_move (to, force_reg (from_mode, from), unsignedp);
        !           593:       return;
        !           594:     }
        !           595: 
        !           596:   if (from_mode == DImode && to_mode == HImode)
        !           597:     {
        !           598: #ifdef HAVE_truncdihi2
        !           599:       if (HAVE_truncdihi2)
        !           600:        {
        !           601:          emit_unop_insn (CODE_FOR_truncdihi2, to, from, UNKNOWN);
        !           602:          return;
        !           603:        }
        !           604: #endif
        !           605:       convert_move (to, force_reg (from_mode, from), unsignedp);
        !           606:       return;
        !           607:     }
        !           608: 
        !           609:   if (from_mode == DImode && to_mode == QImode)
        !           610:     {
        !           611: #ifdef HAVE_truncdiqi2
        !           612:       if (HAVE_truncdiqi2)
        !           613:        {
        !           614:          emit_unop_insn (CODE_FOR_truncdiqi2, to, from, UNKNOWN);
        !           615:          return;
        !           616:        }
        !           617: #endif
        !           618:       convert_move (to, force_reg (from_mode, from), unsignedp);
        !           619:       return;
        !           620:     }
        !           621: 
        !           622:   if (from_mode == SImode && to_mode == HImode)
        !           623:     {
        !           624: #ifdef HAVE_truncsihi2
        !           625:       if (HAVE_truncsihi2)
        !           626:        {
        !           627:          emit_unop_insn (CODE_FOR_truncsihi2, to, from, UNKNOWN);
        !           628:          return;
        !           629:        }
        !           630: #endif
        !           631:       convert_move (to, force_reg (from_mode, from), unsignedp);
        !           632:       return;
        !           633:     }
        !           634: 
        !           635:   if (from_mode == SImode && to_mode == QImode)
        !           636:     {
        !           637: #ifdef HAVE_truncsiqi2
        !           638:       if (HAVE_truncsiqi2)
        !           639:        {
        !           640:          emit_unop_insn (CODE_FOR_truncsiqi2, to, from, UNKNOWN);
        !           641:          return;
        !           642:        }
        !           643: #endif
        !           644:       convert_move (to, force_reg (from_mode, from), unsignedp);
        !           645:       return;
        !           646:     }
        !           647: 
        !           648:   if (from_mode == HImode && to_mode == QImode)
        !           649:     {
        !           650: #ifdef HAVE_trunchiqi2
        !           651:       if (HAVE_trunchiqi2)
        !           652:        {
        !           653:          emit_unop_insn (CODE_FOR_trunchiqi2, to, from, UNKNOWN);
        !           654:          return;
        !           655:        }
        !           656: #endif
        !           657:       convert_move (to, force_reg (from_mode, from), unsignedp);
        !           658:       return;
        !           659:     }
        !           660: 
        !           661:   /* Handle truncation of volatile memrefs, and so on;
        !           662:      the things that couldn't be truncated directly,
        !           663:      and for which there was no special instruction.  */
        !           664:   if (GET_MODE_BITSIZE (to_mode) < GET_MODE_BITSIZE (from_mode))
        !           665:     {
        !           666:       rtx temp = force_reg (to_mode, gen_lowpart (to_mode, from));
        !           667:       emit_move_insn (to, temp);
        !           668:       return;
        !           669:     }
        !           670: 
        !           671:   /* Mode combination is not recognized.  */
        !           672:   abort ();
        !           673: }
        !           674: 
        !           675: /* Return an rtx for a value that would result
        !           676:    from converting X to mode MODE.
        !           677:    Both X and MODE may be floating, or both integer.
        !           678:    UNSIGNEDP is nonzero if X is an unsigned value.
        !           679:    This can be done by referring to a part of X in place
        !           680:    or by copying to a new temporary with conversion.  */
        !           681: 
        !           682: rtx
        !           683: convert_to_mode (mode, x, unsignedp)
        !           684:      enum machine_mode mode;
        !           685:      rtx x;
        !           686:      int unsignedp;
        !           687: {
        !           688:   register rtx temp;
        !           689: 
        !           690:   x = protect_from_queue (x, 0);
        !           691: 
        !           692:   if (mode == GET_MODE (x))
        !           693:     return x;
        !           694: 
        !           695:   /* There is one case that we must handle specially: If we are converting
        !           696:      a CONST_INT into a mode whose size is twice HOST_BITS_PER_INT and
        !           697:      we are to interpret the constant as unsigned, gen_lowpart will do
        !           698:      the wrong if the constant appears negative.  What we want to do is
        !           699:      make the high-order word of the constant zero, not all ones.  */
        !           700: 
        !           701:   if (unsignedp && GET_MODE_CLASS (mode) == MODE_INT
        !           702:       && GET_MODE_BITSIZE (mode) == 2 * HOST_BITS_PER_INT
        !           703:       && GET_CODE (x) == CONST_INT && INTVAL (x) < 0)
        !           704:     return immed_double_const (INTVAL (x), 0, mode);
        !           705: 
        !           706:   /* We can do this with a gen_lowpart if both desired and current modes
        !           707:      are integer, and this is either a constant integer, a register, or a
        !           708:      non-volatile MEM.  Except for the constant case, we must be narrowing
        !           709:      the operand.  */
        !           710: 
        !           711:   if (GET_CODE (x) == CONST_INT
        !           712:       || (GET_MODE_CLASS (mode) == MODE_INT
        !           713:          && GET_MODE_CLASS (GET_MODE (x)) == MODE_INT
        !           714:          && (GET_CODE (x) == CONST_DOUBLE
        !           715:              || (GET_MODE_SIZE (mode) <= GET_MODE_SIZE (GET_MODE (x))
        !           716:                  && ((GET_CODE (x) == MEM && ! MEM_VOLATILE_P (x))
        !           717:                      || GET_CODE (x) == REG)))))
        !           718:     return gen_lowpart (mode, x);
        !           719: 
        !           720:   temp = gen_reg_rtx (mode);
        !           721:   convert_move (temp, x, unsignedp);
        !           722:   return temp;
        !           723: }
        !           724: 
        !           725: /* Generate several move instructions to copy LEN bytes
        !           726:    from block FROM to block TO.  (These are MEM rtx's with BLKmode).
        !           727:    The caller must pass FROM and TO
        !           728:     through protect_from_queue before calling.
        !           729:    ALIGN (in bytes) is maximum alignment we can assume.  */
        !           730: 
        !           731: struct move_by_pieces
        !           732: {
        !           733:   rtx to;
        !           734:   rtx to_addr;
        !           735:   int autinc_to;
        !           736:   int explicit_inc_to;
        !           737:   rtx from;
        !           738:   rtx from_addr;
        !           739:   int autinc_from;
        !           740:   int explicit_inc_from;
        !           741:   int len;
        !           742:   int offset;
        !           743:   int reverse;
        !           744: };
        !           745: 
        !           746: static void move_by_pieces_1 ();
        !           747: static int move_by_pieces_ninsns ();
        !           748: 
        !           749: static void
        !           750: move_by_pieces (to, from, len, align)
        !           751:      rtx to, from;
        !           752:      int len, align;
        !           753: {
        !           754:   struct move_by_pieces data;
        !           755:   rtx to_addr = XEXP (to, 0), from_addr = XEXP (from, 0);
        !           756:   int max_size = 10000;
        !           757: 
        !           758:   data.offset = 0;
        !           759:   data.to_addr = to_addr;
        !           760:   data.from_addr = from_addr;
        !           761:   data.to = to;
        !           762:   data.from = from;
        !           763:   data.autinc_to
        !           764:     = (GET_CODE (to_addr) == PRE_INC || GET_CODE (to_addr) == PRE_DEC
        !           765:        || GET_CODE (to_addr) == POST_INC || GET_CODE (to_addr) == POST_DEC);
        !           766:   data.autinc_from
        !           767:     = (GET_CODE (from_addr) == PRE_INC || GET_CODE (from_addr) == PRE_DEC
        !           768:        || GET_CODE (from_addr) == POST_INC
        !           769:        || GET_CODE (from_addr) == POST_DEC);
        !           770: 
        !           771:   data.explicit_inc_from = 0;
        !           772:   data.explicit_inc_to = 0;
        !           773:   data.reverse
        !           774:     = (GET_CODE (to_addr) == PRE_DEC || GET_CODE (to_addr) == POST_DEC);
        !           775:   if (data.reverse) data.offset = len;
        !           776:   data.len = len;
        !           777: 
        !           778:   /* If copying requires more than two move insns,
        !           779:      copy addresses to registers (to make displacements shorter)
        !           780:      and use post-increment if available.  */
        !           781:   if (!(data.autinc_from && data.autinc_to)
        !           782:       && move_by_pieces_ninsns (len, align) > 2)
        !           783:     {
        !           784: #ifdef HAVE_PRE_DECREMENT
        !           785:       if (data.reverse && ! data.autinc_from)
        !           786:        {
        !           787:          data.from_addr = copy_addr_to_reg (plus_constant (from_addr, len));
        !           788:          data.autinc_from = 1;
        !           789:          data.explicit_inc_from = -1;
        !           790:        }
        !           791: #endif
        !           792: #ifdef HAVE_POST_INCREMENT
        !           793:       if (! data.autinc_from)
        !           794:        {
        !           795:          data.from_addr = copy_addr_to_reg (from_addr);
        !           796:          data.autinc_from = 1;
        !           797:          data.explicit_inc_from = 1;
        !           798:        }
        !           799: #endif
        !           800:       if (!data.autinc_from && CONSTANT_P (from_addr))
        !           801:        data.from_addr = copy_addr_to_reg (from_addr);
        !           802: #ifdef HAVE_PRE_DECREMENT
        !           803:       if (data.reverse && ! data.autinc_to)
        !           804:        {
        !           805:          data.to_addr = copy_addr_to_reg (plus_constant (to_addr, len));
        !           806:          data.autinc_to = 1;
        !           807:          data.explicit_inc_to = -1;
        !           808:        }
        !           809: #endif
        !           810: #ifdef HAVE_POST_INCREMENT
        !           811:       if (! data.reverse && ! data.autinc_to)
        !           812:        {
        !           813:          data.to_addr = copy_addr_to_reg (to_addr);
        !           814:          data.autinc_to = 1;
        !           815:          data.explicit_inc_to = 1;
        !           816:        }
        !           817: #endif
        !           818:       if (!data.autinc_to && CONSTANT_P (to_addr))
        !           819:        data.to_addr = copy_addr_to_reg (to_addr);
        !           820:     }
        !           821: 
        !           822: #if defined (STRICT_ALIGNMENT) || defined (SLOW_UNALIGNED_ACCESS)
        !           823:   if (align > MOVE_MAX || align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT)
        !           824:     align = MOVE_MAX;
        !           825: #else
        !           826:   align = MOVE_MAX;
        !           827: #endif
        !           828: 
        !           829:   /* First move what we can in the largest integer mode, then go to
        !           830:      successively smaller modes.  */
        !           831: 
        !           832:   while (max_size > 1)
        !           833:     {
        !           834:       enum machine_mode mode = VOIDmode, tmode;
        !           835:       enum insn_code icode;
        !           836: 
        !           837:       for (tmode = VOIDmode; (int) tmode < (int) MAX_MACHINE_MODE;
        !           838:           tmode = (enum machine_mode) ((int) tmode + 1))
        !           839:        if (GET_MODE_CLASS (tmode) == MODE_INT
        !           840:            && GET_MODE_SIZE (tmode) < max_size)
        !           841:          mode = tmode;
        !           842: 
        !           843:       if (mode == VOIDmode)
        !           844:        break;
        !           845: 
        !           846:       icode = mov_optab->handlers[(int) mode].insn_code;
        !           847:       if (icode != CODE_FOR_nothing
        !           848:          && align >= MIN (BIGGEST_ALIGNMENT / BITS_PER_UNIT,
        !           849:                           GET_MODE_SIZE (mode)))
        !           850:        move_by_pieces_1 (GEN_FCN (icode), mode, &data);
        !           851: 
        !           852:       max_size = GET_MODE_SIZE (mode);
        !           853:     }
        !           854: 
        !           855:   /* The code above should have handled everything.  */
        !           856:   if (data.len != 0)
        !           857:     abort ();
        !           858: }
        !           859: 
        !           860: /* Return number of insns required to move L bytes by pieces.
        !           861:    ALIGN (in bytes) is maximum alignment we can assume.  */
        !           862: 
        !           863: static int
        !           864: move_by_pieces_ninsns (l, align)
        !           865:      unsigned int l;
        !           866:      int align;
        !           867: {
        !           868:   register int n_insns = 0;
        !           869:   int max_size = 10000;
        !           870: 
        !           871: #if defined (STRICT_ALIGNMENT) || defined (SLOW_UNALIGNED_ACCESS)
        !           872:   if (align > MOVE_MAX || align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT)
        !           873:     align = MOVE_MAX;
        !           874: #else
        !           875:   align = MOVE_MAX;
        !           876: #endif
        !           877: 
        !           878:   while (max_size > 1)
        !           879:     {
        !           880:       enum machine_mode mode = VOIDmode, tmode;
        !           881:       enum insn_code icode;
        !           882: 
        !           883:       for (tmode = VOIDmode; (int) tmode < (int) MAX_MACHINE_MODE;
        !           884:           tmode = (enum machine_mode) ((int) tmode + 1))
        !           885:        if (GET_MODE_CLASS (tmode) == MODE_INT
        !           886:            && GET_MODE_SIZE (tmode) < max_size)
        !           887:          mode = tmode;
        !           888: 
        !           889:       if (mode == VOIDmode)
        !           890:        break;
        !           891: 
        !           892:       icode = mov_optab->handlers[(int) mode].insn_code;
        !           893:       if (icode != CODE_FOR_nothing
        !           894:          && align >= MIN (BIGGEST_ALIGNMENT / BITS_PER_UNIT,
        !           895:                           GET_MODE_SIZE (mode)))
        !           896:        n_insns += l / GET_MODE_SIZE (mode), l %= GET_MODE_SIZE (mode);
        !           897: 
        !           898:       max_size = GET_MODE_SIZE (mode);
        !           899:     }
        !           900: 
        !           901:   return n_insns;
        !           902: }
        !           903: 
        !           904: /* Subroutine of move_by_pieces.  Move as many bytes as appropriate
        !           905:    with move instructions for mode MODE.  GENFUN is the gen_... function
        !           906:    to make a move insn for that mode.  DATA has all the other info.  */
        !           907: 
        !           908: static void
        !           909: move_by_pieces_1 (genfun, mode, data)
        !           910:      rtx (*genfun) ();
        !           911:      enum machine_mode mode;
        !           912:      struct move_by_pieces *data;
        !           913: {
        !           914:   register int size = GET_MODE_SIZE (mode);
        !           915:   register rtx to1, from1;
        !           916: 
        !           917:   while (data->len >= size)
        !           918:     {
        !           919:       if (data->reverse) data->offset -= size;
        !           920: 
        !           921:       to1 = (data->autinc_to
        !           922:             ? gen_rtx (MEM, mode, data->to_addr)
        !           923:             : change_address (data->to, mode,
        !           924:                               plus_constant (data->to_addr, data->offset)));
        !           925:       from1 =
        !           926:        (data->autinc_from
        !           927:         ? gen_rtx (MEM, mode, data->from_addr)
        !           928:         : change_address (data->from, mode,
        !           929:                           plus_constant (data->from_addr, data->offset)));
        !           930: 
        !           931: #ifdef HAVE_PRE_DECREMENT
        !           932:       if (data->explicit_inc_to < 0)
        !           933:        emit_insn (gen_sub2_insn (data->to_addr,
        !           934:                                  gen_rtx (CONST_INT, VOIDmode, size)));
        !           935:       if (data->explicit_inc_from < 0)
        !           936:        emit_insn (gen_sub2_insn (data->from_addr,
        !           937:                                  gen_rtx (CONST_INT, VOIDmode, size)));
        !           938: #endif
        !           939: 
        !           940:       emit_insn ((*genfun) (to1, from1));
        !           941: #ifdef HAVE_POST_INCREMENT
        !           942:       if (data->explicit_inc_to > 0)
        !           943:        emit_insn (gen_add2_insn (data->to_addr,
        !           944:                                  gen_rtx (CONST_INT, VOIDmode, size)));
        !           945:       if (data->explicit_inc_from > 0)
        !           946:        emit_insn (gen_add2_insn (data->from_addr,
        !           947:                                  gen_rtx (CONST_INT, VOIDmode, size)));
        !           948: #endif
        !           949: 
        !           950:       if (! data->reverse) data->offset += size;
        !           951: 
        !           952:       data->len -= size;
        !           953:     }
        !           954: }
        !           955: 
        !           956: /* Emit code to move a block Y to a block X.
        !           957:    This may be done with string-move instructions,
        !           958:    with multiple scalar move instructions, or with a library call.
        !           959: 
        !           960:    Both X and Y must be MEM rtx's (perhaps inside VOLATILE)
        !           961:    with mode BLKmode.
        !           962:    SIZE is an rtx that says how long they are.
        !           963:    ALIGN is the maximum alignment we can assume they have,
        !           964:    measured in bytes.  */
        !           965: 
        !           966: void
        !           967: emit_block_move (x, y, size, align)
        !           968:      rtx x, y;
        !           969:      rtx size;
        !           970:      int align;
        !           971: {
        !           972:   if (GET_MODE (x) != BLKmode)
        !           973:     abort ();
        !           974: 
        !           975:   if (GET_MODE (y) != BLKmode)
        !           976:     abort ();
        !           977: 
        !           978:   x = protect_from_queue (x, 1);
        !           979:   y = protect_from_queue (y, 0);
        !           980: 
        !           981:   if (GET_CODE (x) != MEM)
        !           982:     abort ();
        !           983:   if (GET_CODE (y) != MEM)
        !           984:     abort ();
        !           985:   if (size == 0)
        !           986:     abort ();
        !           987: 
        !           988:   if (GET_CODE (size) == CONST_INT
        !           989:       && (move_by_pieces_ninsns ((unsigned) INTVAL (size), align)
        !           990:          < MOVE_RATIO))
        !           991:     move_by_pieces (x, y, INTVAL (size), align);
        !           992:   else
        !           993:     {
        !           994:       /* Try the most limited insn first, because there's no point
        !           995:         including more than one in the machine description unless
        !           996:         the more limited one has some advantage.  */
        !           997: #ifdef HAVE_movstrqi
        !           998:       if (HAVE_movstrqi
        !           999:          && GET_CODE (size) == CONST_INT
        !          1000:          && ((unsigned) INTVAL (size)
        !          1001:              < (1 << (GET_MODE_BITSIZE (QImode) - 1))))
        !          1002:        {
        !          1003:          rtx insn = gen_movstrqi (x, y, size,
        !          1004:                                   gen_rtx (CONST_INT, VOIDmode, align));
        !          1005:          if (insn)
        !          1006:            {
        !          1007:              emit_insn (insn);
        !          1008:              return;
        !          1009:            }
        !          1010:        }
        !          1011: #endif
        !          1012: #ifdef HAVE_movstrhi
        !          1013:       if (HAVE_movstrhi
        !          1014:          && GET_CODE (size) == CONST_INT
        !          1015:          && ((unsigned) INTVAL (size)
        !          1016:              < (1 << (GET_MODE_BITSIZE (HImode) - 1))))
        !          1017:        {
        !          1018:          rtx insn = gen_movstrhi (x, y, size,
        !          1019:                                   gen_rtx (CONST_INT, VOIDmode, align));
        !          1020:          if (insn)
        !          1021:            {
        !          1022:              emit_insn (insn);
        !          1023:              return;
        !          1024:            }
        !          1025:        }
        !          1026: #endif
        !          1027: #ifdef HAVE_movstrsi
        !          1028:       if (HAVE_movstrsi)
        !          1029:        {
        !          1030:          rtx insn = gen_movstrsi (x, y, size,
        !          1031:                                   gen_rtx (CONST_INT, VOIDmode, align));
        !          1032:          if (insn)
        !          1033:            {
        !          1034:              emit_insn (insn);
        !          1035:              return;
        !          1036:            }
        !          1037:        }
        !          1038: #endif
        !          1039: #ifdef HAVE_movstrdi
        !          1040:       if (HAVE_movstrdi)
        !          1041:        {
        !          1042:          rtx insn = gen_movstrdi (x, y, size,
        !          1043:                                   gen_rtx (CONST_INT, VOIDmode, align));
        !          1044:          if (insn)
        !          1045:            {
        !          1046:              emit_insn (insn);
        !          1047:              return;
        !          1048:            }
        !          1049:        }
        !          1050: #endif
        !          1051: 
        !          1052: #ifdef TARGET_MEM_FUNCTIONS
        !          1053:       emit_library_call (memcpy_libfunc, 0,
        !          1054:                         VOIDmode, 3, XEXP (x, 0), Pmode,
        !          1055:                         XEXP (y, 0), Pmode,
        !          1056:                         size, Pmode);
        !          1057: #else
        !          1058:       emit_library_call (bcopy_libfunc, 0,
        !          1059:                         VOIDmode, 3, XEXP (y, 0), Pmode,
        !          1060:                         XEXP (x, 0), Pmode,
        !          1061:                         size, Pmode);
        !          1062: #endif
        !          1063:     }
        !          1064: }
        !          1065: 
        !          1066: /* Copy all or part of a value X into registers starting at REGNO.
        !          1067:    The number of registers to be filled is NREGS.  */
        !          1068: 
        !          1069: void
        !          1070: move_block_to_reg (regno, x, nregs, mode)
        !          1071:      int regno;
        !          1072:      rtx x;
        !          1073:      int nregs;
        !          1074:      enum machine_mode mode;
        !          1075: {
        !          1076:   int i;
        !          1077:   rtx pat, last;
        !          1078: 
        !          1079:   if (CONSTANT_P (x) && ! LEGITIMATE_CONSTANT_P (x))
        !          1080:     x = validize_mem (force_const_mem (mode, x));
        !          1081: 
        !          1082:   /* See if the machine can do this with a load multiple insn.  */
        !          1083: #ifdef HAVE_load_multiple
        !          1084:   last = get_last_insn ();
        !          1085:   pat = gen_load_multiple (gen_rtx (REG, word_mode, regno), x,
        !          1086:                           gen_rtx (CONST_INT, VOIDmode, nregs));
        !          1087:   if (pat)
        !          1088:     {
        !          1089:       emit_insn (pat);
        !          1090:       return;
        !          1091:     }
        !          1092:   else
        !          1093:     delete_insns_since (last);
        !          1094: #endif
        !          1095: 
        !          1096:   for (i = 0; i < nregs; i++)
        !          1097:     emit_move_insn (gen_rtx (REG, word_mode, regno + i),
        !          1098:                    operand_subword_force (x, i, mode));
        !          1099: }
        !          1100: 
        !          1101: /* Copy all or part of a BLKmode value X out of registers starting at REGNO.
        !          1102:    The number of registers to be filled is NREGS.  */
        !          1103: 
        !          1104: void
        !          1105: move_block_from_reg (regno, x, nregs)
        !          1106:      int regno;
        !          1107:      rtx x;
        !          1108:      int nregs;
        !          1109: {
        !          1110:   int i;
        !          1111:   rtx pat, last;
        !          1112: 
        !          1113:   /* See if the machine can do this with a store multiple insn.  */
        !          1114: #ifdef HAVE_store_multiple
        !          1115:   last = get_last_insn ();
        !          1116:   pat = gen_store_multiple (x, gen_rtx (REG, word_mode, regno),
        !          1117:                            gen_rtx (CONST_INT, VOIDmode, nregs));
        !          1118:   if (pat)
        !          1119:     {
        !          1120:       emit_insn (pat);
        !          1121:       return;
        !          1122:     }
        !          1123:   else
        !          1124:     delete_insns_since (last);
        !          1125: #endif
        !          1126: 
        !          1127:   for (i = 0; i < nregs; i++)
        !          1128:     {
        !          1129:       rtx tem = operand_subword (x, i, 1, BLKmode);
        !          1130: 
        !          1131:       if (tem == 0)
        !          1132:        abort ();
        !          1133: 
        !          1134:       emit_move_insn (tem, gen_rtx (REG, word_mode, regno + i));
        !          1135:     }
        !          1136: }
        !          1137: 
        !          1138: /* Mark NREGS consecutive regs, starting at REGNO, as being live now.  */
        !          1139: 
        !          1140: void
        !          1141: use_regs (regno, nregs)
        !          1142:      int regno;
        !          1143:      int nregs;
        !          1144: {
        !          1145:   int i;
        !          1146: 
        !          1147:   for (i = 0; i < nregs; i++)
        !          1148:     emit_insn (gen_rtx (USE, VOIDmode, gen_rtx (REG, word_mode, regno + i)));
        !          1149: }
        !          1150: 
        !          1151: /* Write zeros through the storage of OBJECT.
        !          1152:    If OBJECT has BLKmode, SIZE is its length in bytes.  */
        !          1153: 
        !          1154: void
        !          1155: clear_storage (object, size)
        !          1156:      rtx object;
        !          1157:      int size;
        !          1158: {
        !          1159:   if (GET_MODE (object) == BLKmode)
        !          1160:     {
        !          1161: #ifdef TARGET_MEM_FUNCTIONS
        !          1162:       emit_library_call (memset_libfunc, 0,
        !          1163:                         VOIDmode, 3,
        !          1164:                         XEXP (object, 0), Pmode, const0_rtx, Pmode,
        !          1165:                         gen_rtx (CONST_INT, VOIDmode, size), Pmode);
        !          1166: #else
        !          1167:       emit_library_call (bzero_libfunc, 0,
        !          1168:                         VOIDmode, 2,
        !          1169:                         XEXP (object, 0), Pmode,
        !          1170:                         gen_rtx (CONST_INT, VOIDmode, size), Pmode);
        !          1171: #endif
        !          1172:     }
        !          1173:   else
        !          1174:     emit_move_insn (object, const0_rtx);
        !          1175: }
        !          1176: 
        !          1177: /* Generate code to copy Y into X.
        !          1178:    Both Y and X must have the same mode, except that
        !          1179:    Y can be a constant with VOIDmode.
        !          1180:    This mode cannot be BLKmode; use emit_block_move for that.
        !          1181: 
        !          1182:    Return the last instruction emitted.  */
        !          1183: 
        !          1184: rtx
        !          1185: emit_move_insn (x, y)
        !          1186:      rtx x, y;
        !          1187: {
        !          1188:   enum machine_mode mode = GET_MODE (x);
        !          1189:   int i;
        !          1190: 
        !          1191:   x = protect_from_queue (x, 1);
        !          1192:   y = protect_from_queue (y, 0);
        !          1193: 
        !          1194:   if (mode == BLKmode || (GET_MODE (y) != mode && GET_MODE (y) != VOIDmode))
        !          1195:     abort ();
        !          1196: 
        !          1197:   if (CONSTANT_P (y) && ! LEGITIMATE_CONSTANT_P (y))
        !          1198:     y = force_const_mem (mode, y);
        !          1199: 
        !          1200:   /* If X or Y are memory references, verify that their addresses are valid
        !          1201:      for the machine.  */
        !          1202:   if (GET_CODE (x) == MEM
        !          1203:       && ((! memory_address_p (GET_MODE (x), XEXP (x, 0))
        !          1204:           && ! push_operand (x, GET_MODE (x)))
        !          1205:          || (flag_force_addr
        !          1206:              && CONSTANT_ADDRESS_P (XEXP (x, 0)))))
        !          1207:     x = change_address (x, VOIDmode, XEXP (x, 0));
        !          1208: 
        !          1209:   if (GET_CODE (y) == MEM
        !          1210:       && (! memory_address_p (GET_MODE (y), XEXP (y, 0))
        !          1211:          || (flag_force_addr
        !          1212:              && CONSTANT_ADDRESS_P (XEXP (y, 0)))))
        !          1213:     y = change_address (y, VOIDmode, XEXP (y, 0));
        !          1214: 
        !          1215:   if (mode == BLKmode)
        !          1216:     abort ();
        !          1217: 
        !          1218:   if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
        !          1219:     return
        !          1220:       emit_insn (GEN_FCN (mov_optab->handlers[(int) mode].insn_code) (x, y));
        !          1221: 
        !          1222:   /* This will handle any multi-word mode that lacks a move_insn pattern.
        !          1223:      However, you will get better code if you define such patterns,
        !          1224:      even if they must turn into multiple assembler instructions.  */
        !          1225:   else if (GET_MODE_SIZE (mode) >= UNITS_PER_WORD)
        !          1226:     {
        !          1227:       rtx last_insn = 0;
        !          1228: 
        !          1229:       for (i = 0;
        !          1230:           i < (GET_MODE_SIZE (mode)  + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD;
        !          1231:           i++)
        !          1232:        {
        !          1233:          rtx xpart = operand_subword (x, i, 1, mode);
        !          1234:          rtx ypart = operand_subword (y, i, 1, mode);
        !          1235: 
        !          1236:          /* If we can't get a part of Y, put Y into memory if it is a
        !          1237:             constant.  Otherwise, force it into a register.  If we still
        !          1238:             can't get a part of Y, abort.  */
        !          1239:          if (ypart == 0 && CONSTANT_P (y))
        !          1240:            {
        !          1241:              y = force_const_mem (mode, y);
        !          1242:              ypart = operand_subword (y, i, 1, mode);
        !          1243:            }
        !          1244:          else if (ypart == 0)
        !          1245:            ypart = operand_subword_force (y, i, mode);
        !          1246: 
        !          1247:          if (xpart == 0 || ypart == 0)
        !          1248:            abort ();
        !          1249: 
        !          1250:          last_insn = emit_move_insn (xpart, ypart);
        !          1251:        }
        !          1252:       return last_insn;
        !          1253:     }
        !          1254:   else
        !          1255:     abort ();
        !          1256: }
        !          1257: 
        !          1258: /* Pushing data onto the stack.  */
        !          1259: 
        !          1260: /* Push a block of length SIZE (perhaps variable)
        !          1261:    and return an rtx to address the beginning of the block.
        !          1262:    Note that it is not possible for the value returned to be a QUEUED.
        !          1263:    The value may be virtual_outgoing_args_rtx.
        !          1264: 
        !          1265:    EXTRA is the number of bytes of padding to push in addition to SIZE.
        !          1266:    BELOW nonzero means this padding comes at low addresses;
        !          1267:    otherwise, the padding comes at high addresses.  */
        !          1268: 
        !          1269: rtx
        !          1270: push_block (size, extra, below)
        !          1271:      rtx size;
        !          1272:      int extra, below;
        !          1273: {
        !          1274:   register rtx temp;
        !          1275:   if (CONSTANT_P (size))
        !          1276:     anti_adjust_stack (plus_constant (size, extra));
        !          1277:   else if (GET_CODE (size) == REG && extra == 0)
        !          1278:     anti_adjust_stack (size);
        !          1279:   else
        !          1280:     {
        !          1281:       rtx temp = copy_to_mode_reg (Pmode, size);
        !          1282:       if (extra != 0)
        !          1283:        temp = expand_binop (Pmode, add_optab,
        !          1284:                             temp,
        !          1285:                             gen_rtx (CONST_INT, VOIDmode, extra),
        !          1286:                             temp, 0, OPTAB_LIB_WIDEN);
        !          1287:       anti_adjust_stack (temp);
        !          1288:     }
        !          1289: 
        !          1290: #ifdef STACK_GROWS_DOWNWARD
        !          1291:   temp = virtual_outgoing_args_rtx;
        !          1292:   if (extra != 0 && below)
        !          1293:     temp = plus_constant (temp, extra);
        !          1294: #else
        !          1295:   if (GET_CODE (size) == CONST_INT)
        !          1296:     temp = plus_constant (virtual_outgoing_args_rtx,
        !          1297:                          - INTVAL (size) - (below ? 0 : extra));
        !          1298:   else if (extra != 0 && !below)
        !          1299:     temp = gen_rtx (PLUS, Pmode, virtual_outgoing_args_rtx,
        !          1300:                    negate_rtx (Pmode, plus_constant (size, extra)));
        !          1301:   else
        !          1302:     temp = gen_rtx (PLUS, Pmode, virtual_outgoing_args_rtx,
        !          1303:                    negate_rtx (Pmode, size));
        !          1304: #endif
        !          1305: 
        !          1306:   return memory_address (GET_CLASS_NARROWEST_MODE (MODE_INT), temp);
        !          1307: }
        !          1308: 
        !          1309: static rtx
        !          1310: gen_push_operand ()
        !          1311: {
        !          1312:   return gen_rtx (STACK_PUSH_CODE, Pmode, stack_pointer_rtx);
        !          1313: }
        !          1314: 
        !          1315: /* Generate code to push X onto the stack, assuming it has mode MODE and
        !          1316:    type TYPE.
        !          1317:    MODE is redundant except when X is a CONST_INT (since they don't
        !          1318:    carry mode info).
        !          1319:    SIZE is an rtx for the size of data to be copied (in bytes),
        !          1320:    needed only if X is BLKmode.
        !          1321: 
        !          1322:    ALIGN (in bytes) is maximum alignment we can assume.
        !          1323: 
        !          1324:    If PARTIAL is nonzero, then copy that many of the first words
        !          1325:    of X into registers starting with REG, and push the rest of X.
        !          1326:    The amount of space pushed is decreased by PARTIAL words,
        !          1327:    rounded *down* to a multiple of PARM_BOUNDARY.
        !          1328:    REG must be a hard register in this case.
        !          1329: 
        !          1330:    EXTRA is the amount in bytes of extra space to leave next to this arg.
        !          1331:    This is ignored if an argument block has already been allocted.
        !          1332: 
        !          1333:    On a machine that lacks real push insns, ARGS_ADDR is the address of
        !          1334:    the bottom of the argument block for this call.  We use indexing off there
        !          1335:    to store the arg.  On machines with push insns, ARGS_ADDR is 0 when a
        !          1336:    argument block has not been preallocated.
        !          1337: 
        !          1338:    ARGS_SO_FAR is the size of args previously pushed for this call.  */
        !          1339: 
        !          1340: void
        !          1341: emit_push_insn (x, mode, type, size, align, partial, reg, extra,
        !          1342:                args_addr, args_so_far)
        !          1343:      register rtx x;
        !          1344:      enum machine_mode mode;
        !          1345:      tree type;
        !          1346:      rtx size;
        !          1347:      int align;
        !          1348:      int partial;
        !          1349:      rtx reg;
        !          1350:      int extra;
        !          1351:      rtx args_addr;
        !          1352:      rtx args_so_far;
        !          1353: {
        !          1354:   rtx xinner;
        !          1355:   enum direction stack_direction
        !          1356: #ifdef STACK_GROWS_DOWNWARD
        !          1357:     = downward;
        !          1358: #else
        !          1359:     = upward;
        !          1360: #endif
        !          1361: 
        !          1362:   /* Decide where to pad the argument: `downward' for below,
        !          1363:      `upward' for above, or `none' for don't pad it.
        !          1364:      Default is below for small data on big-endian machines; else above.  */
        !          1365:   enum direction where_pad = FUNCTION_ARG_PADDING (mode, type);
        !          1366: 
        !          1367:   /* Invert direction if stack is post-update.  */
        !          1368:   if (STACK_PUSH_CODE == POST_INC || STACK_PUSH_CODE == POST_DEC)
        !          1369:     if (where_pad != none)
        !          1370:       where_pad = (where_pad == downward ? upward : downward);
        !          1371: 
        !          1372:   xinner = x = protect_from_queue (x, 0);
        !          1373: 
        !          1374:   if (mode == BLKmode)
        !          1375:     {
        !          1376:       /* Copy a block into the stack, entirely or partially.  */
        !          1377: 
        !          1378:       register rtx temp;
        !          1379:       int used = partial * UNITS_PER_WORD;
        !          1380:       int offset = used % (PARM_BOUNDARY / BITS_PER_UNIT);
        !          1381:       int skip;
        !          1382:       
        !          1383:       if (size == 0)
        !          1384:        abort ();
        !          1385: 
        !          1386:       used -= offset;
        !          1387: 
        !          1388:       /* USED is now the # of bytes we need not copy to the stack
        !          1389:         because registers will take care of them.  */
        !          1390: 
        !          1391:       if (partial != 0)
        !          1392:        xinner = change_address (xinner, BLKmode,
        !          1393:                                 plus_constant (XEXP (xinner, 0), used));
        !          1394: 
        !          1395:       /* If the partial register-part of the arg counts in its stack size,
        !          1396:         skip the part of stack space corresponding to the registers.
        !          1397:         Otherwise, start copying to the beginning of the stack space,
        !          1398:         by setting SKIP to 0.  */
        !          1399: #ifndef REG_PARM_STACK_SPACE
        !          1400:       skip = 0;
        !          1401: #else
        !          1402:       skip = used;
        !          1403: #endif
        !          1404: 
        !          1405: #ifdef PUSH_ROUNDING
        !          1406:       /* Do it with several push insns if that doesn't take lots of insns
        !          1407:         and if there is no difficulty with push insns that skip bytes
        !          1408:         on the stack for alignment purposes.  */
        !          1409:       if (args_addr == 0
        !          1410:          && GET_CODE (size) == CONST_INT
        !          1411:          && skip == 0
        !          1412:          && (move_by_pieces_ninsns ((unsigned) INTVAL (size) - used, align)
        !          1413:              < MOVE_RATIO)
        !          1414: #if defined (STRICT_ALIGNMENT) || defined (SLOW_UNALIGNED_ACCESS)
        !          1415:          /* Here we avoid the case of a structure whose weak alignment
        !          1416:             forces many pushes of a small amount of data,
        !          1417:             and such small pushes do rounding that causes trouble.  */
        !          1418:          && (align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT
        !          1419:              || PUSH_ROUNDING (align) == align)
        !          1420: #endif
        !          1421:          && PUSH_ROUNDING (INTVAL (size)) == INTVAL (size))
        !          1422:        {
        !          1423:          /* Push padding now if padding above and stack grows down,
        !          1424:             or if padding below and stack grows up.
        !          1425:             But if space already allocated, this has already been done.  */
        !          1426:          if (extra && args_addr == 0
        !          1427:              && where_pad != none && where_pad != stack_direction)
        !          1428:            anti_adjust_stack (gen_rtx (CONST_INT, VOIDmode, extra));
        !          1429: 
        !          1430:          move_by_pieces (gen_rtx (MEM, BLKmode, gen_push_operand ()), xinner,
        !          1431:                          INTVAL (size) - used, align);
        !          1432:        }
        !          1433:       else
        !          1434: #endif /* PUSH_ROUNDING */
        !          1435:        {
        !          1436:          /* Otherwise make space on the stack and copy the data
        !          1437:             to the address of that space.  */
        !          1438: 
        !          1439:          /* Deduct words put into registers from the size we must copy.  */
        !          1440:          if (partial != 0)
        !          1441:            {
        !          1442:              if (GET_CODE (size) == CONST_INT)
        !          1443:                size = gen_rtx (CONST_INT, VOIDmode, INTVAL (size) - used);
        !          1444:              else
        !          1445:                size = expand_binop (GET_MODE (size), sub_optab, size,
        !          1446:                                     gen_rtx (CONST_INT, VOIDmode, used),
        !          1447:                                     0, 0, OPTAB_LIB_WIDEN);
        !          1448:            }
        !          1449: 
        !          1450:          /* Get the address of the stack space.
        !          1451:             In this case, we do not deal with EXTRA separately.
        !          1452:             A single stack adjust will do.  */
        !          1453:          if (! args_addr)
        !          1454:            {
        !          1455:              temp = push_block (size, extra, where_pad == downward);
        !          1456:              extra = 0;
        !          1457:            }
        !          1458:          else if (GET_CODE (args_so_far) == CONST_INT)
        !          1459:            temp = memory_address (BLKmode,
        !          1460:                                   plus_constant (args_addr,
        !          1461:                                                  skip + INTVAL (args_so_far)));
        !          1462:          else
        !          1463:            temp = memory_address (BLKmode,
        !          1464:                                   plus_constant (gen_rtx (PLUS, Pmode,
        !          1465:                                                           args_addr, args_so_far),
        !          1466:                                                  skip));
        !          1467: 
        !          1468:          /* TEMP is the address of the block.  Copy the data there.  */
        !          1469:          if (GET_CODE (size) == CONST_INT
        !          1470:              && (move_by_pieces_ninsns ((unsigned) INTVAL (size), align)
        !          1471:                  < MOVE_RATIO))
        !          1472:            {
        !          1473:              move_by_pieces (gen_rtx (MEM, BLKmode, temp), xinner,
        !          1474:                              INTVAL (size), align);
        !          1475:              goto ret;
        !          1476:            }
        !          1477:          /* Try the most limited insn first, because there's no point
        !          1478:             including more than one in the machine description unless
        !          1479:             the more limited one has some advantage.  */
        !          1480: #ifdef HAVE_movstrqi
        !          1481:          if (HAVE_movstrqi
        !          1482:              && GET_CODE (size) == CONST_INT
        !          1483:              && ((unsigned) INTVAL (size)
        !          1484:                  < (1 << (GET_MODE_BITSIZE (QImode) - 1))))
        !          1485:            {
        !          1486:              emit_insn (gen_movstrqi (gen_rtx (MEM, BLKmode, temp),
        !          1487:                                       xinner, size,
        !          1488:                                       gen_rtx (CONST_INT, VOIDmode, align)));
        !          1489:              goto ret;
        !          1490:            }
        !          1491: #endif
        !          1492: #ifdef HAVE_movstrhi
        !          1493:          if (HAVE_movstrhi
        !          1494:              && GET_CODE (size) == CONST_INT
        !          1495:              && ((unsigned) INTVAL (size)
        !          1496:                  < (1 << (GET_MODE_BITSIZE (HImode) - 1))))
        !          1497:            {
        !          1498:              emit_insn (gen_movstrhi (gen_rtx (MEM, BLKmode, temp),
        !          1499:                                       xinner, size,
        !          1500:                                       gen_rtx (CONST_INT, VOIDmode, align)));
        !          1501:              goto ret;
        !          1502:            }
        !          1503: #endif
        !          1504: #ifdef HAVE_movstrsi
        !          1505:          if (HAVE_movstrsi)
        !          1506:            {
        !          1507:              emit_insn (gen_movstrsi (gen_rtx (MEM, BLKmode, temp),
        !          1508:                                       xinner, size,
        !          1509:                                       gen_rtx (CONST_INT, VOIDmode, align)));
        !          1510:              goto ret;
        !          1511:            }
        !          1512: #endif
        !          1513: #ifdef HAVE_movstrdi
        !          1514:          if (HAVE_movstrdi)
        !          1515:            {
        !          1516:              emit_insn (gen_movstrdi (gen_rtx (MEM, BLKmode, temp),
        !          1517:                                       xinner, size,
        !          1518:                                       gen_rtx (CONST_INT, VOIDmode, align)));
        !          1519:              goto ret;
        !          1520:            }
        !          1521: #endif
        !          1522: 
        !          1523: #ifndef ACCUMULATE_OUTGOING_ARGS
        !          1524:          /* If the source is referenced relative to the stack pointer,
        !          1525:             copy it to another register to stabilize it.  We do not need
        !          1526:             to do this if we know that we won't be changing sp.  */
        !          1527: 
        !          1528:          if (reg_mentioned_p (virtual_stack_dynamic_rtx, temp)
        !          1529:              || reg_mentioned_p (virtual_outgoing_args_rtx, temp))
        !          1530:            temp = copy_to_reg (temp);
        !          1531: #endif
        !          1532: 
        !          1533:          /* Make inhibit_defer_pop nonzero around the library call
        !          1534:             to force it to pop the bcopy-arguments right away.  */
        !          1535:          NO_DEFER_POP;
        !          1536: #ifdef TARGET_MEM_FUNCTIONS
        !          1537:          emit_library_call (memcpy_libfunc, 0,
        !          1538:                             VOIDmode, 3, temp, Pmode, XEXP (xinner, 0), Pmode,
        !          1539:                             size, Pmode);
        !          1540: #else
        !          1541:          emit_library_call (bcopy_libfunc, 0,
        !          1542:                             VOIDmode, 3, XEXP (xinner, 0), Pmode, temp, Pmode,
        !          1543:                             size, Pmode);
        !          1544: #endif
        !          1545:          OK_DEFER_POP;
        !          1546:        }
        !          1547:     }
        !          1548:   else if (partial > 0)
        !          1549:     {
        !          1550:       /* Scalar partly in registers.  */
        !          1551: 
        !          1552:       int size = GET_MODE_SIZE (mode) / UNITS_PER_WORD;
        !          1553:       int i;
        !          1554:       int not_stack;
        !          1555:       /* # words of start of argument
        !          1556:         that we must make space for but need not store.  */
        !          1557:       int offset = partial % (PARM_BOUNDARY / BITS_PER_WORD);
        !          1558:       int args_offset = INTVAL (args_so_far);
        !          1559:       int skip;
        !          1560: 
        !          1561:       /* Push padding now if padding above and stack grows down,
        !          1562:         or if padding below and stack grows up.
        !          1563:         But if space already allocated, this has already been done.  */
        !          1564:       if (extra && args_addr == 0
        !          1565:          && where_pad != none && where_pad != stack_direction)
        !          1566:        anti_adjust_stack (gen_rtx (CONST_INT, VOIDmode, extra));
        !          1567: 
        !          1568:       /* If we make space by pushing it, we might as well push
        !          1569:         the real data.  Otherwise, we can leave OFFSET nonzero
        !          1570:         and leave the space uninitialized.  */
        !          1571:       if (args_addr == 0)
        !          1572:        offset = 0;
        !          1573: 
        !          1574:       /* Now NOT_STACK gets the number of words that we don't need to
        !          1575:         allocate on the stack.  */
        !          1576:       not_stack = partial - offset;
        !          1577: 
        !          1578:       /* If the partial register-part of the arg counts in its stack size,
        !          1579:         skip the part of stack space corresponding to the registers.
        !          1580:         Otherwise, start copying to the beginning of the stack space,
        !          1581:         by setting SKIP to 0.  */
        !          1582: #ifndef REG_PARM_STACK_SPACE
        !          1583:       skip = 0;
        !          1584: #else
        !          1585:       skip = not_stack;
        !          1586: #endif
        !          1587: 
        !          1588:       if (CONSTANT_P (x) && ! LEGITIMATE_CONSTANT_P (x))
        !          1589:        x = validize_mem (force_const_mem (mode, x));
        !          1590: 
        !          1591:       /* If X is a hard register in a non-integer mode, copy it into a pseudo;
        !          1592:         SUBREGs of such registers are not allowed.  */
        !          1593:       if ((GET_CODE (x) == REG && REGNO (x) < FIRST_PSEUDO_REGISTER
        !          1594:           && GET_MODE_CLASS (GET_MODE (x)) != MODE_INT))
        !          1595:        x = copy_to_reg (x);
        !          1596: 
        !          1597:       /* Loop over all the words allocated on the stack for this arg.  */
        !          1598:       /* We can do it by words, because any scalar bigger than a word
        !          1599:         has a size a multiple of a word.  */
        !          1600: #ifndef PUSH_ARGS_REVERSED
        !          1601:       for (i = not_stack; i < size; i++)
        !          1602: #else
        !          1603:       for (i = size - 1; i >= not_stack; i--)
        !          1604: #endif
        !          1605:        if (i >= not_stack + offset)
        !          1606:          emit_push_insn (operand_subword_force (x, i, mode),
        !          1607:                          word_mode, 0, 0, align, 0, 0, 0, args_addr,
        !          1608:                          gen_rtx (CONST_INT, VOIDmode,
        !          1609:                                   args_offset + ((i - not_stack + skip)
        !          1610:                                                  * UNITS_PER_WORD)));
        !          1611:     }
        !          1612:   else
        !          1613:     {
        !          1614:       rtx addr;
        !          1615: 
        !          1616:       /* Push padding now if padding above and stack grows down,
        !          1617:         or if padding below and stack grows up.
        !          1618:         But if space already allocated, this has already been done.  */
        !          1619:       if (extra && args_addr == 0
        !          1620:          && where_pad != none && where_pad != stack_direction)
        !          1621:        anti_adjust_stack (gen_rtx (CONST_INT, VOIDmode, extra));
        !          1622: 
        !          1623: #ifdef PUSH_ROUNDING
        !          1624:       if (args_addr == 0)
        !          1625:        addr = gen_push_operand ();
        !          1626:       else
        !          1627: #endif
        !          1628:        if (GET_CODE (args_so_far) == CONST_INT)
        !          1629:          addr
        !          1630:            = memory_address (mode,
        !          1631:                              plus_constant (args_addr, INTVAL (args_so_far)));
        !          1632:       else
        !          1633:        addr = memory_address (mode, gen_rtx (PLUS, Pmode, args_addr,
        !          1634:                                              args_so_far));
        !          1635: 
        !          1636:       emit_move_insn (gen_rtx (MEM, mode, addr), x);
        !          1637:     }
        !          1638: 
        !          1639:  ret:
        !          1640:   /* If part should go in registers, copy that part
        !          1641:      into the appropriate registers.  Do this now, at the end,
        !          1642:      since mem-to-mem copies above may do function calls.  */
        !          1643:   if (partial > 0)
        !          1644:     move_block_to_reg (REGNO (reg), x, partial, mode);
        !          1645: 
        !          1646:   if (extra && args_addr == 0 && where_pad == stack_direction)
        !          1647:     anti_adjust_stack (gen_rtx (CONST_INT, VOIDmode, extra));
        !          1648: }
        !          1649: 
        !          1650: /* Output a library call to function FUN (a SYMBOL_REF rtx)
        !          1651:    (emitting the queue unless NO_QUEUE is nonzero),
        !          1652:    for a value of mode OUTMODE,
        !          1653:    with NARGS different arguments, passed as alternating rtx values
        !          1654:    and machine_modes to convert them to.
        !          1655:    The rtx values should have been passed through protect_from_queue already.
        !          1656: 
        !          1657:    NO_QUEUE will be true if and only if the library call is a `const' call
        !          1658:    which will be enclosed in REG_LIBCALL/REG_RETVAL notes; it is equivalent
        !          1659:    to the variable is_const in expand_call.  */
        !          1660: 
        !          1661: void
        !          1662: emit_library_call (va_alist)
        !          1663:      va_dcl
        !          1664: {
        !          1665:   va_list p;
        !          1666:   struct args_size args_size;
        !          1667:   register int argnum;
        !          1668:   enum machine_mode outmode;
        !          1669:   int nargs;
        !          1670:   rtx fun;
        !          1671:   rtx orgfun;
        !          1672:   int inc;
        !          1673:   int count;
        !          1674:   rtx argblock = 0;
        !          1675:   CUMULATIVE_ARGS args_so_far;
        !          1676:   struct arg { rtx value; enum machine_mode mode; rtx reg; int partial;
        !          1677:               struct args_size offset; struct args_size size; };
        !          1678:   struct arg *argvec;
        !          1679:   int old_inhibit_defer_pop = inhibit_defer_pop;
        !          1680:   int no_queue = 0;
        !          1681:   rtx use_insns;
        !          1682: 
        !          1683:   va_start (p);
        !          1684:   orgfun = fun = va_arg (p, rtx);
        !          1685:   no_queue = va_arg (p, int);
        !          1686:   outmode = va_arg (p, enum machine_mode);
        !          1687:   nargs = va_arg (p, int);
        !          1688: 
        !          1689:   /* Copy all the libcall-arguments out of the varargs data
        !          1690:      and into a vector ARGVEC.
        !          1691: 
        !          1692:      Compute how to pass each argument.  We only support a very small subset
        !          1693:      of the full argument passing conventions to limit complexity here since
        !          1694:      library functions shouldn't have many args.  */
        !          1695: 
        !          1696:   argvec = (struct arg *) alloca (nargs * sizeof (struct arg));
        !          1697: 
        !          1698:   INIT_CUMULATIVE_ARGS (args_so_far, (tree)0, fun);
        !          1699: 
        !          1700:   args_size.constant = 0;
        !          1701:   args_size.var = 0;
        !          1702: 
        !          1703:   for (count = 0; count < nargs; count++)
        !          1704:     {
        !          1705:       rtx val = va_arg (p, rtx);
        !          1706:       enum machine_mode mode = va_arg (p, enum machine_mode);
        !          1707: 
        !          1708:       /* We cannot convert the arg value to the mode the library wants here;
        !          1709:         must do it earlier where we know the signedness of the arg.  */
        !          1710:       if (mode == BLKmode
        !          1711:          || (GET_MODE (val) != mode && GET_MODE (val) != VOIDmode))
        !          1712:        abort ();
        !          1713: 
        !          1714:       /* On some machines, there's no way to pass a float to a library fcn.
        !          1715:         Pass it as a double instead.  */
        !          1716: #ifdef LIBGCC_NEEDS_DOUBLE
        !          1717:       if (LIBGCC_NEEDS_DOUBLE && mode == SFmode)
        !          1718:        val = convert_to_mode (DFmode, val), mode = DFmode;
        !          1719: #endif
        !          1720: 
        !          1721:       /* Make sure it is a reasonable operand for a move or push insn.  */
        !          1722:       if (GET_CODE (val) != REG && GET_CODE (val) != MEM
        !          1723:          && ! (CONSTANT_P (val) && LEGITIMATE_CONSTANT_P (val)))
        !          1724:        val = force_operand (val, 0);
        !          1725: 
        !          1726:       argvec[count].value = val;
        !          1727:       argvec[count].mode = mode;
        !          1728: 
        !          1729: #ifdef FUNCTION_ARG_PASS_BY_REFERENCE
        !          1730:       if (FUNCTION_ARG_PASS_BY_REFERENCE (args_so_far, mode, (tree)0, 1))
        !          1731:        abort ();
        !          1732: #endif
        !          1733: 
        !          1734:       argvec[count].reg = FUNCTION_ARG (args_so_far, mode, (tree)0, 1);
        !          1735:       if (argvec[count].reg && GET_CODE (argvec[count].reg) == EXPR_LIST)
        !          1736:        abort ();
        !          1737: #ifdef FUNCTION_ARG_PARTIAL_NREGS
        !          1738:       argvec[count].partial
        !          1739:        = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode, (tree)0, 1);
        !          1740: #else
        !          1741:       argvec[count].partial = 0;
        !          1742: #endif
        !          1743: 
        !          1744:       locate_and_pad_parm (mode, 0,
        !          1745:                           argvec[count].reg && argvec[count].partial == 0,
        !          1746:                           0, &args_size, &argvec[count].offset,
        !          1747:                           &argvec[count].size);
        !          1748: 
        !          1749:       if (argvec[count].size.var)
        !          1750:        abort ();
        !          1751: 
        !          1752: #ifndef REG_PARM_STACK_SPACE
        !          1753:       if (argvec[count].partial)
        !          1754:        argvec[count].size.constant -= argvec[count].partial * UNITS_PER_WORD;
        !          1755: #endif
        !          1756: 
        !          1757:       if (argvec[count].reg == 0 || argvec[count].partial != 0
        !          1758: #ifdef REG_PARM_STACK_SPACE
        !          1759:          || 1
        !          1760: #endif
        !          1761:          )
        !          1762:        args_size.constant += argvec[count].size.constant;
        !          1763: 
        !          1764: #ifdef ACCUMULATE_OUTGOING_ARGS
        !          1765:       /* If this arg is actually passed on the stack, it might be
        !          1766:         clobbering something we already put there (this library call might
        !          1767:         be inside the evaluation of an argument to a function whose call
        !          1768:         requires the stack).  This will only occur when the library call
        !          1769:         has sufficient args to run out of argument registers.  Abort in
        !          1770:         this case; if this ever occurs, code must be added to save and
        !          1771:         restore the arg slot.  */
        !          1772: 
        !          1773:       if (argvec[count].reg == 0 || argvec[count].partial != 0)
        !          1774:        abort ();
        !          1775: #endif
        !          1776: 
        !          1777:       FUNCTION_ARG_ADVANCE (args_so_far, mode, (tree)0, 1);
        !          1778:     }
        !          1779:   va_end (p);
        !          1780: 
        !          1781:   /* If this machine requires an external definition for library
        !          1782:      functions, write one out.  */
        !          1783:   assemble_external_libcall (fun);
        !          1784: 
        !          1785: #ifdef STACK_BOUNDARY
        !          1786:   args_size.constant = (((args_size.constant + (STACK_BYTES - 1))
        !          1787:                         / STACK_BYTES) * STACK_BYTES);
        !          1788: #endif
        !          1789: 
        !          1790: #ifdef REG_PARM_STACK_SPACE
        !          1791:   args_size.constant = MAX (args_size.constant,
        !          1792:                            REG_PARM_STACK_SPACE ((tree) 0));
        !          1793: #endif
        !          1794: 
        !          1795: #ifdef ACCUMULATE_OUTGOING_ARGS
        !          1796:   if (args_size.constant > current_function_outgoing_args_size)
        !          1797:     current_function_outgoing_args_size = args_size.constant;
        !          1798:   args_size.constant = 0;
        !          1799: #endif
        !          1800: 
        !          1801: #ifndef PUSH_ROUNDING
        !          1802:   argblock = push_block (gen_rtx (CONST_INT, VOIDmode, args_size.constant),
        !          1803:                         0, 0);
        !          1804: #endif
        !          1805: 
        !          1806: #ifdef PUSH_ARGS_REVERSED
        !          1807:   inc = -1;
        !          1808:   argnum = nargs - 1;
        !          1809: #else
        !          1810:   inc = 1;
        !          1811:   argnum = 0;
        !          1812: #endif
        !          1813: 
        !          1814:   /* Push the args that need to be pushed.  */
        !          1815: 
        !          1816:   for (count = 0; count < nargs; count++, argnum += inc)
        !          1817:     {
        !          1818:       register enum machine_mode mode = argvec[argnum].mode;
        !          1819:       register rtx val = argvec[argnum].value;
        !          1820:       rtx reg = argvec[argnum].reg;
        !          1821:       int partial = argvec[argnum].partial;
        !          1822: 
        !          1823:       if (! (reg != 0 && partial == 0))
        !          1824:        emit_push_insn (val, mode, 0, 0, 0, partial, reg, 0, argblock,
        !          1825:                        gen_rtx (CONST_INT, VOIDmode,
        !          1826:                                 argvec[count].offset.constant));
        !          1827:       NO_DEFER_POP;
        !          1828:     }
        !          1829: 
        !          1830: #ifdef PUSH_ARGS_REVERSED
        !          1831:   argnum = nargs - 1;
        !          1832: #else
        !          1833:   argnum = 0;
        !          1834: #endif
        !          1835: 
        !          1836:   /* Now load any reg parms into their regs.  */
        !          1837: 
        !          1838:   for (count = 0; count < nargs; count++, argnum += inc)
        !          1839:     {
        !          1840:       register enum machine_mode mode = argvec[argnum].mode;
        !          1841:       register rtx val = argvec[argnum].value;
        !          1842:       rtx reg = argvec[argnum].reg;
        !          1843:       int partial = argvec[argnum].partial;
        !          1844: 
        !          1845:       if (reg != 0 && partial == 0)
        !          1846:        emit_move_insn (reg, val);
        !          1847:       NO_DEFER_POP;
        !          1848:     }
        !          1849: 
        !          1850:   /* For version 1.37, try deleting this entirely.  */
        !          1851:   if (! no_queue)
        !          1852:     emit_queue ();
        !          1853: 
        !          1854:   /* Any regs containing parms remain in use through the call.  */
        !          1855:   start_sequence ();
        !          1856:   for (count = 0; count < nargs; count++)
        !          1857:     if (argvec[count].reg != 0)
        !          1858:       emit_insn (gen_rtx (USE, VOIDmode, argvec[count].reg));
        !          1859: 
        !          1860:   use_insns = get_insns ();
        !          1861:   end_sequence ();
        !          1862: 
        !          1863:   fun = prepare_call_address (fun, 0, &use_insns);
        !          1864: 
        !          1865:   /* Don't allow popping to be deferred, since then
        !          1866:      cse'ing of library calls could delete a call and leave the pop.  */
        !          1867:   NO_DEFER_POP;
        !          1868: 
        !          1869:   /* We pass the old value of inhibit_defer_pop + 1 to emit_call_1, which
        !          1870:      will set inhibit_defer_pop to that value.  */
        !          1871: 
        !          1872:   emit_call_1 (fun, get_identifier (XSTR (orgfun, 0)), args_size.constant, 0,
        !          1873:               FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1),
        !          1874:               outmode != VOIDmode ? hard_libcall_value (outmode) : 0,
        !          1875:               old_inhibit_defer_pop + 1, use_insns, no_queue);
        !          1876: 
        !          1877:   /* Now restore inhibit_defer_pop to its actual original value.  */
        !          1878:   OK_DEFER_POP;
        !          1879: }
        !          1880: 
        !          1881: /* Expand an assignment that stores the value of FROM into TO.
        !          1882:    If WANT_VALUE is nonzero, return an rtx for the value of TO.
        !          1883:    (This may contain a QUEUED rtx.)
        !          1884:    Otherwise, the returned value is not meaningful.
        !          1885: 
        !          1886:    SUGGEST_REG is no longer actually used.
        !          1887:    It used to mean, copy the value through a register
        !          1888:    and return that register, if that is possible.
        !          1889:    But now we do this if WANT_VALUE.
        !          1890: 
        !          1891:    If the value stored is a constant, we return the constant.  */
        !          1892: 
        !          1893: rtx
        !          1894: expand_assignment (to, from, want_value, suggest_reg)
        !          1895:      tree to, from;
        !          1896:      int want_value;
        !          1897:      int suggest_reg;
        !          1898: {
        !          1899:   register rtx to_rtx = 0;
        !          1900:   rtx result;
        !          1901: 
        !          1902:   /* Don't crash if the lhs of the assignment was erroneous.  */
        !          1903: 
        !          1904:   if (TREE_CODE (to) == ERROR_MARK)
        !          1905:     return expand_expr (from, 0, VOIDmode, 0);
        !          1906: 
        !          1907:   /* Assignment of a structure component needs special treatment
        !          1908:      if the structure component's rtx is not simply a MEM.
        !          1909:      Assignment of an array element at a constant index
        !          1910:      has the same problem.  */
        !          1911: 
        !          1912:   if (TREE_CODE (to) == COMPONENT_REF
        !          1913:       || TREE_CODE (to) == BIT_FIELD_REF
        !          1914:       || (TREE_CODE (to) == ARRAY_REF
        !          1915:          && TREE_CODE (TREE_OPERAND (to, 1)) == INTEGER_CST
        !          1916:          && TREE_CODE (TYPE_SIZE (TREE_TYPE (to))) == INTEGER_CST))
        !          1917:     {
        !          1918:       enum machine_mode mode1;
        !          1919:       int bitsize;
        !          1920:       int bitpos;
        !          1921:       int unsignedp;
        !          1922:       int volatilep = 0;
        !          1923:       tree tem = get_inner_reference (to, &bitsize, &bitpos,
        !          1924:                                      &mode1, &unsignedp, &volatilep);
        !          1925: 
        !          1926:       /* If we are going to use store_bit_field and extract_bit_field,
        !          1927:         make sure to_rtx will be safe for multiple use.  */
        !          1928: 
        !          1929:       if (mode1 == VOIDmode && want_value)
        !          1930:        tem = stabilize_reference (tem);
        !          1931: 
        !          1932:       to_rtx = expand_expr (tem, 0, VOIDmode, 0);
        !          1933:       if (volatilep)
        !          1934:        {
        !          1935:          if (GET_CODE (to_rtx) == MEM)
        !          1936:            MEM_VOLATILE_P (to_rtx) = 1;
        !          1937: #if 0  /* This was turned off because, when a field is volatile
        !          1938:          in an object which is not volatile, the object may be in a register,
        !          1939:          and then we would abort over here.  */
        !          1940:          else
        !          1941:            abort ();
        !          1942: #endif
        !          1943:        }
        !          1944: 
        !          1945:       result = store_field (to_rtx, bitsize, bitpos, mode1, from,
        !          1946:                            (want_value
        !          1947:                             /* Spurious cast makes HPUX compiler happy.  */
        !          1948:                             ? (enum machine_mode) TYPE_MODE (TREE_TYPE (to))
        !          1949:                             : VOIDmode),
        !          1950:                            unsignedp,
        !          1951:                            /* Required alignment of containing datum.  */
        !          1952:                            TYPE_ALIGN (TREE_TYPE (tem)) / BITS_PER_UNIT,
        !          1953:                            int_size_in_bytes (TREE_TYPE (tem)));
        !          1954:       preserve_temp_slots (result);
        !          1955:       free_temp_slots ();
        !          1956: 
        !          1957:       return result;
        !          1958:     }
        !          1959: 
        !          1960:   /* Ordinary treatment.  Expand TO to get a REG or MEM rtx.
        !          1961:      Don't re-expand if it was expanded already (in COMPONENT_REF case).  */
        !          1962: 
        !          1963:   if (to_rtx == 0)
        !          1964:     to_rtx = expand_expr (to, 0, VOIDmode, 0);
        !          1965: 
        !          1966:   /* In case we are returning the contents of an object which overlaps
        !          1967:      the place the value is being stored, use a safe function when copying
        !          1968:      a value through a pointer into a structure value return block.  */
        !          1969:   if (TREE_CODE (to) == RESULT_DECL && TREE_CODE (from) == INDIRECT_REF
        !          1970:       && current_function_returns_struct
        !          1971:       && !current_function_returns_pcc_struct)
        !          1972:     {
        !          1973:       rtx from_rtx = expand_expr (from, 0, VOIDmode, 0);
        !          1974:       rtx size = expr_size (from);
        !          1975: 
        !          1976: #ifdef TARGET_MEM_FUNCTIONS
        !          1977:       emit_library_call (memcpy_libfunc, 0,
        !          1978:                         VOIDmode, 3, XEXP (to_rtx, 0), Pmode,
        !          1979:                         XEXP (from_rtx, 0), Pmode,
        !          1980:                         size, Pmode);
        !          1981: #else
        !          1982:       emit_library_call (bcopy_libfunc, 0,
        !          1983:                         VOIDmode, 3, XEXP (from_rtx, 0), Pmode,
        !          1984:                         XEXP (to_rtx, 0), Pmode,
        !          1985:                         size, Pmode);
        !          1986: #endif
        !          1987: 
        !          1988:       preserve_temp_slots (to_rtx);
        !          1989:       free_temp_slots ();
        !          1990:       return to_rtx;
        !          1991:     }
        !          1992: 
        !          1993:   /* Compute FROM and store the value in the rtx we got.  */
        !          1994: 
        !          1995:   result = store_expr (from, to_rtx, want_value);
        !          1996:   preserve_temp_slots (result);
        !          1997:   free_temp_slots ();
        !          1998:   return result;
        !          1999: }
        !          2000: 
        !          2001: /* Generate code for computing expression EXP,
        !          2002:    and storing the value into TARGET.
        !          2003:    Returns TARGET or an equivalent value.
        !          2004:    TARGET may contain a QUEUED rtx.
        !          2005: 
        !          2006:    If SUGGEST_REG is nonzero, copy the value through a register
        !          2007:    and return that register, if that is possible.
        !          2008: 
        !          2009:    If the value stored is a constant, we return the constant.  */
        !          2010: 
        !          2011: rtx
        !          2012: store_expr (exp, target, suggest_reg)
        !          2013:      register tree exp;
        !          2014:      register rtx target;
        !          2015:      int suggest_reg;
        !          2016: {
        !          2017:   register rtx temp;
        !          2018:   int dont_return_target = 0;
        !          2019: 
        !          2020:   if (TREE_CODE (exp) == COMPOUND_EXPR)
        !          2021:     {
        !          2022:       /* Perform first part of compound expression, then assign from second
        !          2023:         part.  */
        !          2024:       expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0);
        !          2025:       emit_queue ();
        !          2026:       return store_expr (TREE_OPERAND (exp, 1), target, suggest_reg);
        !          2027:     }
        !          2028:   else if (TREE_CODE (exp) == COND_EXPR && GET_MODE (target) == BLKmode)
        !          2029:     {
        !          2030:       /* For conditional expression, get safe form of the target.  Then
        !          2031:         test the condition, doing the appropriate assignment on either
        !          2032:         side.  This avoids the creation of unnecessary temporaries.
        !          2033:         For non-BLKmode, it is more efficient not to do this.  */
        !          2034: 
        !          2035:       rtx lab1 = gen_label_rtx (), lab2 = gen_label_rtx ();
        !          2036: 
        !          2037:       emit_queue ();
        !          2038:       target = protect_from_queue (target, 1);
        !          2039: 
        !          2040:       NO_DEFER_POP;
        !          2041:       jumpifnot (TREE_OPERAND (exp, 0), lab1);
        !          2042:       store_expr (TREE_OPERAND (exp, 1), target, suggest_reg);
        !          2043:       emit_queue ();
        !          2044:       emit_jump_insn (gen_jump (lab2));
        !          2045:       emit_barrier ();
        !          2046:       emit_label (lab1);
        !          2047:       store_expr (TREE_OPERAND (exp, 2), target, suggest_reg);
        !          2048:       emit_queue ();
        !          2049:       emit_label (lab2);
        !          2050:       OK_DEFER_POP;
        !          2051:       return target;
        !          2052:     }
        !          2053:   else if (suggest_reg && GET_CODE (target) == MEM
        !          2054:           && GET_MODE (target) != BLKmode)
        !          2055:     /* If target is in memory and caller wants value in a register instead,
        !          2056:        arrange that.  Pass TARGET as target for expand_expr so that,
        !          2057:        if EXP is another assignment, SUGGEST_REG will be nonzero for it.
        !          2058:        We know expand_expr will not use the target in that case.  */
        !          2059:     {
        !          2060:       temp = expand_expr (exp, cse_not_expected ? 0 : target,
        !          2061:                          GET_MODE (target), 0);
        !          2062:       if (GET_MODE (temp) != BLKmode && GET_MODE (temp) != VOIDmode)
        !          2063:        temp = copy_to_reg (temp);
        !          2064:       dont_return_target = 1;
        !          2065:     }
        !          2066:   else if (queued_subexp_p (target))
        !          2067:     /* If target contains a postincrement, it is not safe
        !          2068:        to use as the returned value.  It would access the wrong
        !          2069:        place by the time the queued increment gets output.
        !          2070:        So copy the value through a temporary and use that temp
        !          2071:        as the result.  */
        !          2072:     {
        !          2073:       if (GET_MODE (target) != BLKmode && GET_MODE (target) != VOIDmode)
        !          2074:        {
        !          2075:          /* Expand EXP into a new pseudo.  */
        !          2076:          temp = gen_reg_rtx (GET_MODE (target));
        !          2077:          temp = expand_expr (exp, temp, GET_MODE (target), 0);
        !          2078:        }
        !          2079:       else
        !          2080:        temp = expand_expr (exp, 0, GET_MODE (target), 0);
        !          2081:       dont_return_target = 1;
        !          2082:     }
        !          2083:   else
        !          2084:     {
        !          2085:       temp = expand_expr (exp, target, GET_MODE (target), 0);
        !          2086:       /* DO return TARGET if it's a specified hardware register.
        !          2087:         expand_return relies on this.  */
        !          2088:       if (!(target && GET_CODE (target) == REG
        !          2089:            && REGNO (target) < FIRST_PSEUDO_REGISTER)
        !          2090:          && CONSTANT_P (temp))
        !          2091:        dont_return_target = 1;
        !          2092:     }
        !          2093: 
        !          2094:   /* If value was not generated in the target, store it there.
        !          2095:      Convert the value to TARGET's type first if nec.  */
        !          2096: 
        !          2097:   if (temp != target && TREE_CODE (exp) != ERROR_MARK)
        !          2098:     {
        !          2099:       target = protect_from_queue (target, 1);
        !          2100:       if (GET_MODE (temp) != GET_MODE (target)
        !          2101:          && GET_MODE (temp) != VOIDmode)
        !          2102:        {
        !          2103:          int unsignedp = TREE_UNSIGNED (TREE_TYPE (exp));
        !          2104:          if (dont_return_target)
        !          2105:            {
        !          2106:              /* In this case, we will return TEMP,
        !          2107:                 so make sure it has the proper mode.
        !          2108:                 But don't forget to store the value into TARGET.  */
        !          2109:              temp = convert_to_mode (GET_MODE (target), temp, unsignedp);
        !          2110:              emit_move_insn (target, temp);
        !          2111:            }
        !          2112:          else
        !          2113:            convert_move (target, temp, unsignedp);
        !          2114:        }
        !          2115: 
        !          2116:       else if (GET_MODE (temp) == BLKmode && TREE_CODE (exp) == STRING_CST)
        !          2117:        {
        !          2118:          /* Handle copying a string constant into an array.
        !          2119:             The string constant may be shorter than the array.
        !          2120:             So copy just the string's actual length, and clear the rest.  */
        !          2121:          rtx size;
        !          2122: 
        !          2123:          emit_block_move (target, temp,
        !          2124:                           gen_rtx (CONST_INT, VOIDmode,
        !          2125:                                    TREE_STRING_LENGTH (exp)),
        !          2126:                           TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
        !          2127: 
        !          2128:          temp = plus_constant (XEXP (target, 0), TREE_STRING_LENGTH (exp));
        !          2129:          size = plus_constant (expr_size (exp), - TREE_STRING_LENGTH (exp));
        !          2130:          if (size != const0_rtx)
        !          2131:            {
        !          2132: #ifdef TARGET_MEM_FUNCTIONS
        !          2133:              emit_library_call (memset_libfunc, 0, VOIDmode, 3,
        !          2134:                                 temp, Pmode, const0_rtx, Pmode, size, Pmode);
        !          2135: #else
        !          2136:              emit_library_call (bzero_libfunc, 0, VOIDmode, 2,
        !          2137:                                 temp, Pmode, size, Pmode);
        !          2138: #endif
        !          2139:            }
        !          2140:        }
        !          2141:       else if (GET_MODE (temp) == BLKmode)
        !          2142:        emit_block_move (target, temp, expr_size (exp),
        !          2143:                         TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
        !          2144:       else
        !          2145:        emit_move_insn (target, temp);
        !          2146:     }
        !          2147:   if (dont_return_target)
        !          2148:     return temp;
        !          2149:   return target;
        !          2150: }
        !          2151: 
        !          2152: /* Store the value of constructor EXP into the rtx TARGET.
        !          2153:    TARGET is either a REG or a MEM.  */
        !          2154: 
        !          2155: static void
        !          2156: store_constructor (exp, target)
        !          2157:      tree exp;
        !          2158:      rtx target;
        !          2159: {
        !          2160:   /* We know our target cannot conflict, since safe_from_p has been called.  */
        !          2161: #if 0
        !          2162:   /* Don't try copying piece by piece into a hard register
        !          2163:      since that is vulnerable to being clobbered by EXP.
        !          2164:      Instead, construct in a pseudo register and then copy it all.  */
        !          2165:   if (GET_CODE (target) == REG && REGNO (target) < FIRST_PSEUDO_REGISTER)
        !          2166:     {
        !          2167:       rtx temp = gen_reg_rtx (GET_MODE (target));
        !          2168:       store_constructor (exp, temp);
        !          2169:       emit_move_insn (target, temp);
        !          2170:       return;
        !          2171:     }
        !          2172: #endif
        !          2173: 
        !          2174:   if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE
        !          2175:       || TREE_CODE (TREE_TYPE (exp)) == UNION_TYPE)
        !          2176:     {
        !          2177:       register tree elt;
        !          2178: 
        !          2179:       if (TREE_CODE (TREE_TYPE (exp)) == UNION_TYPE)
        !          2180:        /* Inform later passes that the whole union value is dead.  */
        !          2181:        emit_insn (gen_rtx (CLOBBER, VOIDmode, target));
        !          2182:       /* If the constructor has fewer fields than the structure,
        !          2183:         clear the whole structure first.  */
        !          2184:       else if (list_length (CONSTRUCTOR_ELTS (exp))
        !          2185:               != list_length (TYPE_FIELDS (TREE_TYPE (exp))))
        !          2186:        clear_storage (target, int_size_in_bytes (TREE_TYPE (exp)));
        !          2187:       else
        !          2188:        /* Inform later passes that the old value is dead.  */
        !          2189:        emit_insn (gen_rtx (CLOBBER, VOIDmode, target));
        !          2190: 
        !          2191:       /* Store each element of the constructor into
        !          2192:         the corresponding field of TARGET.  */
        !          2193: 
        !          2194:       for (elt = CONSTRUCTOR_ELTS (exp); elt; elt = TREE_CHAIN (elt))
        !          2195:        {
        !          2196:          register tree field = TREE_PURPOSE (elt);
        !          2197:          register enum machine_mode mode;
        !          2198:          int bitsize;
        !          2199:          int bitpos;
        !          2200:          int unsignedp;
        !          2201: 
        !          2202:          bitsize = TREE_INT_CST_LOW (DECL_SIZE (field));
        !          2203:          unsignedp = TREE_UNSIGNED (field);
        !          2204:          mode = DECL_MODE (field);
        !          2205:          if (DECL_BIT_FIELD (field))
        !          2206:            mode = VOIDmode;
        !          2207: 
        !          2208:          if (TREE_CODE (DECL_FIELD_BITPOS (field)) != INTEGER_CST)
        !          2209:            /* ??? This case remains to be written.  */
        !          2210:            abort ();
        !          2211: 
        !          2212:          bitpos = TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field));
        !          2213: 
        !          2214:          store_field (target, bitsize, bitpos, mode, TREE_VALUE (elt),
        !          2215:                       /* The alignment of TARGET is
        !          2216:                          at least what its type requires.  */
        !          2217:                       VOIDmode, 0,
        !          2218:                       TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT,
        !          2219:                       int_size_in_bytes (TREE_TYPE (exp)));
        !          2220:        }
        !          2221:     }
        !          2222:   else if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
        !          2223:     {
        !          2224:       register tree elt;
        !          2225:       register int i;
        !          2226:       tree domain = TYPE_DOMAIN (TREE_TYPE (exp));
        !          2227:       int minelt = TREE_INT_CST_LOW (TYPE_MIN_VALUE (domain));
        !          2228:       int maxelt = TREE_INT_CST_LOW (TYPE_MAX_VALUE (domain));
        !          2229:       tree elttype = TREE_TYPE (TREE_TYPE (exp));
        !          2230: 
        !          2231:       /* If the constructor has fewer fields than the structure,
        !          2232:         clear the whole structure first.  */
        !          2233: 
        !          2234:       if (list_length (CONSTRUCTOR_ELTS (exp)) < maxelt - minelt + 1)
        !          2235:        clear_storage (target, maxelt - minelt + 1);
        !          2236:       else
        !          2237:        /* Inform later passes that the old value is dead.  */
        !          2238:        emit_insn (gen_rtx (CLOBBER, VOIDmode, target));
        !          2239: 
        !          2240:       /* Store each element of the constructor into
        !          2241:         the corresponding element of TARGET, determined
        !          2242:         by counting the elements.  */
        !          2243:       for (elt = CONSTRUCTOR_ELTS (exp), i = 0;
        !          2244:           elt;
        !          2245:           elt = TREE_CHAIN (elt), i++)
        !          2246:        {
        !          2247:          register enum machine_mode mode;
        !          2248:          int bitsize;
        !          2249:          int bitpos;
        !          2250:          int unsignedp;
        !          2251: 
        !          2252:          mode = TYPE_MODE (elttype);
        !          2253:          bitsize = GET_MODE_BITSIZE (mode);
        !          2254:          unsignedp = TREE_UNSIGNED (elttype);
        !          2255: 
        !          2256:          bitpos = (i * TREE_INT_CST_LOW (TYPE_SIZE (elttype)));
        !          2257: 
        !          2258:          store_field (target, bitsize, bitpos, mode, TREE_VALUE (elt),
        !          2259:                       /* The alignment of TARGET is
        !          2260:                          at least what its type requires.  */
        !          2261:                       VOIDmode, 0,
        !          2262:                       TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT,
        !          2263:                       int_size_in_bytes (TREE_TYPE (exp)));
        !          2264:        }
        !          2265:     }
        !          2266: 
        !          2267:   else
        !          2268:     abort ();
        !          2269: }
        !          2270: 
        !          2271: /* Store the value of EXP (an expression tree)
        !          2272:    into a subfield of TARGET which has mode MODE and occupies
        !          2273:    BITSIZE bits, starting BITPOS bits from the start of TARGET.
        !          2274:    If MODE is VOIDmode, it means that we are storing into a bit-field.
        !          2275: 
        !          2276:    If VALUE_MODE is VOIDmode, return nothing in particular.
        !          2277:    UNSIGNEDP is not used in this case.
        !          2278: 
        !          2279:    Otherwise, return an rtx for the value stored.  This rtx
        !          2280:    has mode VALUE_MODE if that is convenient to do.
        !          2281:    In this case, UNSIGNEDP must be nonzero if the value is an unsigned type.
        !          2282: 
        !          2283:    ALIGN is the alignment that TARGET is known to have, measured in bytes.
        !          2284:    TOTAL_SIZE is the size in bytes of the structure, or -1 if varying.  */
        !          2285: 
        !          2286: static rtx
        !          2287: store_field (target, bitsize, bitpos, mode, exp, value_mode,
        !          2288:             unsignedp, align, total_size)
        !          2289:      rtx target;
        !          2290:      int bitsize, bitpos;
        !          2291:      enum machine_mode mode;
        !          2292:      tree exp;
        !          2293:      enum machine_mode value_mode;
        !          2294:      int unsignedp;
        !          2295:      int align;
        !          2296:      int total_size;
        !          2297: {
        !          2298:   int width_mask = 0;
        !          2299: 
        !          2300:   if (bitsize < HOST_BITS_PER_INT)
        !          2301:     width_mask = (1 << bitsize) - 1;
        !          2302: 
        !          2303:   /* If we are storing into an unaligned field of an aligned union that is
        !          2304:      in a register, we may have the mode of TARGET being an integer mode but
        !          2305:      MODE == BLKmode.  In that case, get an aligned object whose size and
        !          2306:      alignment are the same as TARGET and store TARGET into it (we can avoid
        !          2307:      the store if the field being stored is the entire width of TARGET).  Then
        !          2308:      call ourselves recursively to store the field into a BLKmode version of
        !          2309:      that object.  Finally, load from the object into TARGET.  This is not
        !          2310:      very efficient in general, but should only be slightly more expensive
        !          2311:      than the otherwise-required unaligned accesses.  Perhaps this can be
        !          2312:      cleaned up later.  */
        !          2313: 
        !          2314:   if (mode == BLKmode
        !          2315:       && (GET_CODE (target) == REG || GET_CODE (target) == SUBREG))
        !          2316:     {
        !          2317:       rtx object = assign_stack_temp (GET_MODE (target),
        !          2318:                                      GET_MODE_SIZE (GET_MODE (target)), 0);
        !          2319:       rtx blk_object = copy_rtx (object);
        !          2320: 
        !          2321:       PUT_MODE (blk_object, BLKmode);
        !          2322: 
        !          2323:       if (bitsize != GET_MODE_BITSIZE (GET_MODE (target)))
        !          2324:        emit_move_insn (object, target);
        !          2325: 
        !          2326:       store_field (blk_object, bitsize, bitpos, mode, exp, VOIDmode, 0,
        !          2327:                   align, total_size);
        !          2328: 
        !          2329:       emit_move_insn (target, object);
        !          2330: 
        !          2331:       return target;
        !          2332:     }
        !          2333: 
        !          2334:   /* If the structure is in a register or if the component
        !          2335:      is a bit field, we cannot use addressing to access it.
        !          2336:      Use bit-field techniques or SUBREG to store in it.  */
        !          2337: 
        !          2338:   if (mode == VOIDmode || GET_CODE (target) == REG
        !          2339:       || GET_CODE (target) == SUBREG)
        !          2340:     {
        !          2341:       rtx temp = expand_expr (exp, 0, VOIDmode, 0);
        !          2342:       /* Store the value in the bitfield.  */
        !          2343:       store_bit_field (target, bitsize, bitpos, mode, temp, align, total_size);
        !          2344:       if (value_mode != VOIDmode)
        !          2345:        {
        !          2346:          /* The caller wants an rtx for the value.  */
        !          2347:          /* If possible, avoid refetching from the bitfield itself.  */
        !          2348:          if (width_mask != 0
        !          2349:              && ! (GET_CODE (target) == MEM && MEM_VOLATILE_P (target)))
        !          2350:            return expand_and (temp,
        !          2351:                               gen_rtx (CONST_INT, VOIDmode, width_mask), 0);
        !          2352:          return extract_bit_field (target, bitsize, bitpos, unsignedp,
        !          2353:                                    0, value_mode, 0, align, total_size);
        !          2354:        }
        !          2355:       return const0_rtx;
        !          2356:     }
        !          2357:   else
        !          2358:     {
        !          2359:       rtx addr = XEXP (target, 0);
        !          2360:       rtx to_rtx;
        !          2361: 
        !          2362:       /* If a value is wanted, it must be the lhs;
        !          2363:         so make the address stable for multiple use.  */
        !          2364: 
        !          2365:       if (value_mode != VOIDmode && GET_CODE (addr) != REG
        !          2366:          && ! CONSTANT_ADDRESS_P (addr)
        !          2367:          /* A frame-pointer reference is already stable.  */
        !          2368:          && ! (GET_CODE (addr) == PLUS
        !          2369:                && GET_CODE (XEXP (addr, 1)) == CONST_INT
        !          2370:                && (XEXP (addr, 0) == virtual_incoming_args_rtx
        !          2371:                    || XEXP (addr, 0) == virtual_stack_vars_rtx)))
        !          2372:        addr = copy_to_reg (addr);
        !          2373: 
        !          2374:       /* Now build a reference to just the desired component.  */
        !          2375: 
        !          2376:       to_rtx = change_address (target, mode,
        !          2377:                               plus_constant (addr, (bitpos / BITS_PER_UNIT)));
        !          2378:       MEM_IN_STRUCT_P (to_rtx) = 1;
        !          2379: 
        !          2380:       return store_expr (exp, to_rtx, value_mode != VOIDmode);
        !          2381:     }
        !          2382: }
        !          2383: 
        !          2384: /* Given an expression EXP that may be a COMPONENT_REF, a BIT_FIELD_REF,
        !          2385:    or an ARRAY_REF, look for nested COMPONENT_REFs, BIT_FIELD_REFs, or
        !          2386:    ARRAY_REFs at constant positions and find the ultimate containing object,
        !          2387:    which we return.
        !          2388: 
        !          2389:    We set *PBITSIZE to the size in bits that we want, *PBITPOS to the
        !          2390:    bit position, and *PUNSIGNEDP to the signedness of the field.
        !          2391: 
        !          2392:    If any of the extraction expressions is volatile,
        !          2393:    we store 1 in *PVOLATILEP.  Otherwise we don't change that.
        !          2394: 
        !          2395:    If the field is a bit-field, *PMODE is set to VOIDmode.  Otherwise, it
        !          2396:    is a mode that can be used to access the field.  In that case, *PBITSIZE
        !          2397:    is redundant.  */
        !          2398: 
        !          2399: tree
        !          2400: get_inner_reference (exp, pbitsize, pbitpos, pmode, punsignedp, pvolatilep)
        !          2401:      tree exp;
        !          2402:      int *pbitsize;
        !          2403:      int *pbitpos;
        !          2404:      enum machine_mode *pmode;
        !          2405:      int *punsignedp;
        !          2406:      int *pvolatilep;
        !          2407: {
        !          2408:   tree size_tree = 0;
        !          2409:   enum machine_mode mode = VOIDmode;
        !          2410: 
        !          2411:   if (TREE_CODE (exp) == COMPONENT_REF)
        !          2412:     {
        !          2413:       size_tree = DECL_SIZE (TREE_OPERAND (exp, 1));
        !          2414:       if (! DECL_BIT_FIELD (TREE_OPERAND (exp, 1)))
        !          2415:        mode = DECL_MODE (TREE_OPERAND (exp, 1));
        !          2416:       *punsignedp = TREE_UNSIGNED (TREE_OPERAND (exp, 1));
        !          2417:     }
        !          2418:   else if (TREE_CODE (exp) == BIT_FIELD_REF)
        !          2419:     {
        !          2420:       size_tree = TREE_OPERAND (exp, 1);
        !          2421:       *punsignedp = TREE_UNSIGNED (exp);
        !          2422:     }
        !          2423:   else
        !          2424:     {
        !          2425:       mode = TYPE_MODE (TREE_TYPE (exp));
        !          2426:       *pbitsize = GET_MODE_BITSIZE (mode);
        !          2427:       *punsignedp = TREE_UNSIGNED (TREE_TYPE (exp));
        !          2428:     }
        !          2429:       
        !          2430:   if (size_tree)
        !          2431:     {
        !          2432:       if (TREE_CODE (size_tree) != INTEGER_CST)
        !          2433:        abort ();
        !          2434: 
        !          2435:       *pbitsize = TREE_INT_CST_LOW (size_tree);
        !          2436:     }
        !          2437: 
        !          2438:   /* Compute cumulative bit-offset for nested component-refs and array-refs,
        !          2439:      and find the ultimate containing object.  */
        !          2440: 
        !          2441:   *pbitpos = 0;
        !          2442: 
        !          2443:   while (1)
        !          2444:     {
        !          2445:       if (TREE_CODE (exp) == COMPONENT_REF)
        !          2446:        {
        !          2447:          tree field = TREE_OPERAND (exp, 1);
        !          2448: 
        !          2449:          if (TREE_CODE (DECL_FIELD_BITPOS (field)) != INTEGER_CST)
        !          2450:            /* ??? This case remains to be written.  */
        !          2451:            abort ();
        !          2452: 
        !          2453:          *pbitpos += TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field));
        !          2454:          if (TREE_THIS_VOLATILE (exp))
        !          2455:            *pvolatilep = 1;
        !          2456:        }
        !          2457:       else if (TREE_CODE (exp) == BIT_FIELD_REF)
        !          2458:        {
        !          2459:          if (TREE_CODE (TREE_OPERAND (exp, 2)) != INTEGER_CST)
        !          2460:            /* ??? This case remains to be written.  */
        !          2461:            abort ();
        !          2462: 
        !          2463:          *pbitpos += TREE_INT_CST_LOW (TREE_OPERAND (exp, 2));
        !          2464:          if (TREE_THIS_VOLATILE (exp))
        !          2465:            *pvolatilep = 1;
        !          2466:        }
        !          2467:       else if (TREE_CODE (exp) == ARRAY_REF
        !          2468:               && TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
        !          2469:               && TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) == INTEGER_CST)
        !          2470:        {
        !          2471:          *pbitpos += (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1))
        !          2472:                       * TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (exp))));
        !          2473:          if (TREE_THIS_VOLATILE (exp))
        !          2474:            *pvolatilep = 1;
        !          2475:        }
        !          2476:       else if (TREE_CODE (exp) != NON_LVALUE_EXPR
        !          2477:               && ! ((TREE_CODE (exp) == NOP_EXPR
        !          2478:                      || TREE_CODE (exp) == CONVERT_EXPR)
        !          2479:                     && (TYPE_MODE (TREE_TYPE (exp))
        !          2480:                         == TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))))
        !          2481:        break;
        !          2482:       exp = TREE_OPERAND (exp, 0);
        !          2483:     }
        !          2484: 
        !          2485:   /* If this was a bit-field, see if there is a mode that allows direct
        !          2486:      access in case EXP is in memory.  */
        !          2487:   if (mode == VOIDmode && *pbitpos % *pbitsize == 0)
        !          2488:     {
        !          2489:       mode = mode_for_size (*pbitsize, MODE_INT, 0);
        !          2490:       if (mode == BLKmode)
        !          2491:        mode = VOIDmode;
        !          2492:     }
        !          2493: 
        !          2494:   *pmode = mode;
        !          2495: 
        !          2496:   return exp;
        !          2497: }
        !          2498: 
        !          2499: /* Given an rtx VALUE that may contain additions and multiplications,
        !          2500:    return an equivalent value that just refers to a register or memory.
        !          2501:    This is done by generating instructions to perform the arithmetic
        !          2502:    and returning a pseudo-register containing the value.  */
        !          2503: 
        !          2504: rtx
        !          2505: force_operand (value, target)
        !          2506:      rtx value, target;
        !          2507: {
        !          2508:   register optab binoptab = 0;
        !          2509:   /* Use a temporary to force order of execution of calls to
        !          2510:      `force_operand'.  */
        !          2511:   rtx tmp;
        !          2512:   register rtx op2;
        !          2513:   /* Use subtarget as the target for operand 0 of a binary operation.  */
        !          2514:   register rtx subtarget = (target != 0 && GET_CODE (target) == REG ? target : 0);
        !          2515: 
        !          2516:   if (GET_CODE (value) == PLUS)
        !          2517:     binoptab = add_optab;
        !          2518:   else if (GET_CODE (value) == MINUS)
        !          2519:     binoptab = sub_optab;
        !          2520:   else if (GET_CODE (value) == MULT)
        !          2521:     {
        !          2522:       op2 = XEXP (value, 1);
        !          2523:       if (!CONSTANT_P (op2)
        !          2524:          && !(GET_CODE (op2) == REG && op2 != subtarget))
        !          2525:        subtarget = 0;
        !          2526:       tmp = force_operand (XEXP (value, 0), subtarget);
        !          2527:       return expand_mult (GET_MODE (value), tmp,
        !          2528:                          force_operand (op2, 0),
        !          2529:                          target, 0);
        !          2530:     }
        !          2531: 
        !          2532:   if (binoptab)
        !          2533:     {
        !          2534:       op2 = XEXP (value, 1);
        !          2535:       if (!CONSTANT_P (op2)
        !          2536:          && !(GET_CODE (op2) == REG && op2 != subtarget))
        !          2537:        subtarget = 0;
        !          2538:       if (binoptab == sub_optab && GET_CODE (op2) == CONST_INT)
        !          2539:        {
        !          2540:          binoptab = add_optab;
        !          2541:          op2 = negate_rtx (GET_MODE (value), op2);
        !          2542:        }
        !          2543: 
        !          2544:       /* Check for an addition with OP2 a constant integer and our first
        !          2545:         operand a PLUS of a virtual register and something else.  In that
        !          2546:         case, we want to emit the sum of the virtual register and the
        !          2547:         constant first and then add the other value.  This allows virtual
        !          2548:         register instantiation to simply modify the constant rather than
        !          2549:         creating another one around this addition.  */
        !          2550:       if (binoptab == add_optab && GET_CODE (op2) == CONST_INT
        !          2551:          && GET_CODE (XEXP (value, 0)) == PLUS
        !          2552:          && GET_CODE (XEXP (XEXP (value, 0), 0)) == REG
        !          2553:          && REGNO (XEXP (XEXP (value, 0), 0)) >= FIRST_VIRTUAL_REGISTER
        !          2554:          && REGNO (XEXP (XEXP (value, 0), 0)) <= LAST_VIRTUAL_REGISTER)
        !          2555:        {
        !          2556:          rtx temp = expand_binop (GET_MODE (value), binoptab,
        !          2557:                                   XEXP (XEXP (value, 0), 0), op2,
        !          2558:                                   subtarget, 0, OPTAB_LIB_WIDEN);
        !          2559:          return expand_binop (GET_MODE (value), binoptab, temp,
        !          2560:                               force_operand (XEXP (XEXP (value, 0), 1), 0),
        !          2561:                               target, 0, OPTAB_LIB_WIDEN);
        !          2562:        }
        !          2563:                                   
        !          2564:       tmp = force_operand (XEXP (value, 0), subtarget);
        !          2565:       return expand_binop (GET_MODE (value), binoptab, tmp,
        !          2566:                           force_operand (op2, 0),
        !          2567:                           target, 0, OPTAB_LIB_WIDEN);
        !          2568:       /* We give UNSIGNEP = 0 to expand_binop
        !          2569:         because the only operations we are expanding here are signed ones.  */
        !          2570:     }
        !          2571:   return value;
        !          2572: }
        !          2573: 
        !          2574: /* Subroutine of expand_expr:
        !          2575:    save the non-copied parts (LIST) of an expr (LHS), and return a list
        !          2576:    which can restore these values to their previous values,
        !          2577:    should something modify their storage.  */
        !          2578: 
        !          2579: static tree
        !          2580: save_noncopied_parts (lhs, list)
        !          2581:      tree lhs;
        !          2582:      tree list;
        !          2583: {
        !          2584:   tree tail;
        !          2585:   tree parts = 0;
        !          2586: 
        !          2587:   for (tail = list; tail; tail = TREE_CHAIN (tail))
        !          2588:     if (TREE_CODE (TREE_VALUE (tail)) == TREE_LIST)
        !          2589:       parts = chainon (parts, save_noncopied_parts (lhs, TREE_VALUE (tail)));
        !          2590:     else
        !          2591:       {
        !          2592:        tree part = TREE_VALUE (tail);
        !          2593:        tree part_type = TREE_TYPE (part);
        !          2594:        tree to_be_saved = build (COMPONENT_REF, part_type, lhs, part, 0);
        !          2595:        rtx target = assign_stack_temp (TYPE_MODE (part_type),
        !          2596:                                        int_size_in_bytes (part_type), 0);
        !          2597:        if (! memory_address_p (TYPE_MODE (part_type), XEXP (target, 0)))
        !          2598:          target = change_address (target, TYPE_MODE (part_type), 0);
        !          2599:        parts = tree_cons (to_be_saved,
        !          2600:                           build (RTL_EXPR, part_type, 0, (tree) target),
        !          2601:                           parts);
        !          2602:        store_expr (TREE_PURPOSE (parts), RTL_EXPR_RTL (TREE_VALUE (parts)), 0);
        !          2603:       }
        !          2604:   return parts;
        !          2605: }
        !          2606: 
        !          2607: /* Subroutine of expand_expr:
        !          2608:    record the non-copied parts (LIST) of an expr (LHS), and return a list
        !          2609:    which specifies the initial values of these parts.  */
        !          2610: 
        !          2611: static tree
        !          2612: init_noncopied_parts (lhs, list)
        !          2613:      tree lhs;
        !          2614:      tree list;
        !          2615: {
        !          2616:   tree tail;
        !          2617:   tree parts = 0;
        !          2618: 
        !          2619:   for (tail = list; tail; tail = TREE_CHAIN (tail))
        !          2620:     if (TREE_CODE (TREE_VALUE (tail)) == TREE_LIST)
        !          2621:       parts = chainon (parts, init_noncopied_parts (lhs, TREE_VALUE (tail)));
        !          2622:     else
        !          2623:       {
        !          2624:        tree part = TREE_VALUE (tail);
        !          2625:        tree part_type = TREE_TYPE (part);
        !          2626:        tree to_be_initialized = build (COMPONENT_REF, part_type, lhs, part, 0);
        !          2627:        parts = tree_cons (TREE_PURPOSE (tail), to_be_initialized, parts);
        !          2628:       }
        !          2629:   return parts;
        !          2630: }
        !          2631: 
        !          2632: /* Subroutine of expand_expr: return nonzero iff there is no way that
        !          2633:    EXP can reference X, which is being modified.  */
        !          2634: 
        !          2635: static int
        !          2636: safe_from_p (x, exp)
        !          2637:      rtx x;
        !          2638:      tree exp;
        !          2639: {
        !          2640:   rtx exp_rtl = 0;
        !          2641:   int i, nops;
        !          2642: 
        !          2643:   if (x == 0)
        !          2644:     return 1;
        !          2645: 
        !          2646:   /* If this is a subreg of a hard register, declare it unsafe, otherwise,
        !          2647:      find the underlying pseudo.  */
        !          2648:   if (GET_CODE (x) == SUBREG)
        !          2649:     {
        !          2650:       x = SUBREG_REG (x);
        !          2651:       if (GET_CODE (x) == REG && REGNO (x) < FIRST_PSEUDO_REGISTER)
        !          2652:        return 0;
        !          2653:     }
        !          2654: 
        !          2655:   /* If X is a location in the outgoing argument area, it is always safe.  */
        !          2656:   if (GET_CODE (x) == MEM
        !          2657:       && (XEXP (x, 0) == virtual_outgoing_args_rtx
        !          2658:          || (GET_CODE (XEXP (x, 0)) == PLUS
        !          2659:              && XEXP (XEXP (x, 0), 0) == virtual_outgoing_args_rtx)))
        !          2660:     return 1;
        !          2661: 
        !          2662:   switch (TREE_CODE_CLASS (TREE_CODE (exp)))
        !          2663:     {
        !          2664:     case 'd':
        !          2665:       exp_rtl = DECL_RTL (exp);
        !          2666:       break;
        !          2667: 
        !          2668:     case 'c':
        !          2669:       return 1;
        !          2670: 
        !          2671:     case 'x':
        !          2672:       if (TREE_CODE (exp) == TREE_LIST)
        !          2673:        return (safe_from_p (x, TREE_VALUE (exp))
        !          2674:                && (TREE_CHAIN (exp) == 0
        !          2675:                    || safe_from_p (x, TREE_CHAIN (exp))));
        !          2676:       else
        !          2677:        return 0;
        !          2678: 
        !          2679:     case '1':
        !          2680:       return safe_from_p (x, TREE_OPERAND (exp, 0));
        !          2681: 
        !          2682:     case '2':
        !          2683:     case '<':
        !          2684:       return (safe_from_p (x, TREE_OPERAND (exp, 0))
        !          2685:              && safe_from_p (x, TREE_OPERAND (exp, 1)));
        !          2686: 
        !          2687:     case 'e':
        !          2688:     case 'r':
        !          2689:       /* Now do code-specific tests.  EXP_RTL is set to any rtx we find in
        !          2690:         the expression.  If it is set, we conflict iff we are that rtx or
        !          2691:         both are in memory.  Otherwise, we check all operands of the
        !          2692:         expression recursively.  */
        !          2693: 
        !          2694:       switch (TREE_CODE (exp))
        !          2695:        {
        !          2696:        case ADDR_EXPR:
        !          2697:          return staticp (TREE_OPERAND (exp, 0));
        !          2698: 
        !          2699:        case INDIRECT_REF:
        !          2700:          if (GET_CODE (x) == MEM)
        !          2701:            return 0;
        !          2702:          break;
        !          2703: 
        !          2704:        case CALL_EXPR:
        !          2705:          exp_rtl = CALL_EXPR_RTL (exp);
        !          2706:          if (exp_rtl == 0)
        !          2707:            {
        !          2708:              /* Assume that the call will clobber all hard registers and
        !          2709:                 all of memory.  */
        !          2710:              if ((GET_CODE (x) == REG && REGNO (x) < FIRST_PSEUDO_REGISTER)
        !          2711:                  || GET_CODE (x) == MEM)
        !          2712:                return 0;
        !          2713:            }
        !          2714: 
        !          2715:          break;
        !          2716: 
        !          2717:        case RTL_EXPR:
        !          2718:          exp_rtl = RTL_EXPR_RTL (exp);
        !          2719:          if (exp_rtl == 0)
        !          2720:            /* We don't know what this can modify.  */
        !          2721:            return 0;
        !          2722: 
        !          2723:          break;
        !          2724: 
        !          2725:        case WITH_CLEANUP_EXPR:
        !          2726:          exp_rtl = RTL_EXPR_RTL (exp);
        !          2727:          break;
        !          2728: 
        !          2729:        case SAVE_EXPR:
        !          2730:          exp_rtl = SAVE_EXPR_RTL (exp);
        !          2731:          break;
        !          2732: 
        !          2733:        case METHOD_CALL_EXPR:
        !          2734:          /* This takes a rtx argument, but shouldn't appear here. */
        !          2735:          abort ();
        !          2736:        }
        !          2737: 
        !          2738:       /* If we have an rtx, we do not need to scan our operands.  */
        !          2739:       if (exp_rtl)
        !          2740:        break;
        !          2741: 
        !          2742:       nops = tree_code_length[(int) TREE_CODE (exp)];
        !          2743:       for (i = 0; i < nops; i++)
        !          2744:        if (TREE_OPERAND (exp, i) != 0
        !          2745:            && ! safe_from_p (x, TREE_OPERAND (exp, i)))
        !          2746:          return 0;
        !          2747:     }
        !          2748: 
        !          2749:   /* If we have an rtl, find any enclosed object.  Then see if we conflict
        !          2750:      with it.  */
        !          2751:   if (exp_rtl)
        !          2752:     {
        !          2753:       if (GET_CODE (exp_rtl) == SUBREG)
        !          2754:        {
        !          2755:          exp_rtl = SUBREG_REG (exp_rtl);
        !          2756:          if (GET_CODE (exp_rtl) == REG
        !          2757:              && REGNO (exp_rtl) < FIRST_PSEUDO_REGISTER)
        !          2758:            return 0;
        !          2759:        }
        !          2760: 
        !          2761:       /* If the rtl is X, then it is not safe.  Otherwise, it is unless both
        !          2762:         are memory and EXP is not readonly.  */
        !          2763:       return ! (rtx_equal_p (x, exp_rtl)
        !          2764:                || (GET_CODE (x) == MEM && GET_CODE (exp_rtl) == MEM
        !          2765:                    && ! TREE_READONLY (exp)));
        !          2766:     }
        !          2767: 
        !          2768:   /* If we reach here, it is safe.  */
        !          2769:   return 1;
        !          2770: }
        !          2771: 
        !          2772: /* Subroutine of expand_expr: return nonzero iff EXP is an
        !          2773:    expression whose type is statically determinable.  */
        !          2774: 
        !          2775: static int
        !          2776: fixed_type_p (exp)
        !          2777:      tree exp;
        !          2778: {
        !          2779:   if (TREE_CODE (exp) == PARM_DECL
        !          2780:       || TREE_CODE (exp) == VAR_DECL
        !          2781:       || TREE_CODE (exp) == CALL_EXPR || TREE_CODE (exp) == TARGET_EXPR
        !          2782:       || TREE_CODE (exp) == COMPONENT_REF
        !          2783:       || TREE_CODE (exp) == ARRAY_REF)
        !          2784:     return 1;
        !          2785:   return 0;
        !          2786: }
        !          2787: 
        !          2788: /* expand_expr: generate code for computing expression EXP.
        !          2789:    An rtx for the computed value is returned.  The value is never null.
        !          2790:    In the case of a void EXP, const0_rtx is returned.
        !          2791: 
        !          2792:    The value may be stored in TARGET if TARGET is nonzero.
        !          2793:    TARGET is just a suggestion; callers must assume that
        !          2794:    the rtx returned may not be the same as TARGET.
        !          2795: 
        !          2796:    If TARGET is CONST0_RTX, it means that the value will be ignored.
        !          2797: 
        !          2798:    If TMODE is not VOIDmode, it suggests generating the
        !          2799:    result in mode TMODE.  But this is done only when convenient.
        !          2800:    Otherwise, TMODE is ignored and the value generated in its natural mode.
        !          2801:    TMODE is just a suggestion; callers must assume that
        !          2802:    the rtx returned may not have mode TMODE.
        !          2803: 
        !          2804:    EXPAND_CONST_ADDRESS says that it is okay to return a MEM
        !          2805:    with a constant address even if that address is not normally legitimate.
        !          2806:    EXPAND_INITIALIZER and EXPAND_SUM also have this effect.
        !          2807: 
        !          2808:    If MODIFIER is EXPAND_SUM then when EXP is an addition
        !          2809:    we can return an rtx of the form (MULT (REG ...) (CONST_INT ...))
        !          2810:    or a nest of (PLUS ...) and (MINUS ...) where the terms are
        !          2811:    products as above, or REG or MEM, or constant.
        !          2812:    Ordinarily in such cases we would output mul or add instructions
        !          2813:    and then return a pseudo reg containing the sum.
        !          2814: 
        !          2815:    EXPAND_INITIALIZER is much like EXPAND_SUM except that
        !          2816:    it also marks a label as absolutely required (it can't be dead).
        !          2817:    This is used for outputting expressions used in intializers.  */
        !          2818: 
        !          2819: rtx
        !          2820: expand_expr (exp, target, tmode, modifier)
        !          2821:      register tree exp;
        !          2822:      rtx target;
        !          2823:      enum machine_mode tmode;
        !          2824:      enum expand_modifier modifier;
        !          2825: {
        !          2826:   register rtx op0, op1, temp;
        !          2827:   tree type = TREE_TYPE (exp);
        !          2828:   int unsignedp = TREE_UNSIGNED (type);
        !          2829:   register enum machine_mode mode = TYPE_MODE (type);
        !          2830:   register enum tree_code code = TREE_CODE (exp);
        !          2831:   optab this_optab;
        !          2832:   /* Use subtarget as the target for operand 0 of a binary operation.  */
        !          2833:   rtx subtarget = (target != 0 && GET_CODE (target) == REG ? target : 0);
        !          2834:   rtx original_target = target;
        !          2835:   int ignore = target == const0_rtx;
        !          2836:   tree context;
        !          2837: 
        !          2838:   /* Don't use hard regs as subtargets, because the combiner
        !          2839:      can only handle pseudo regs.  */
        !          2840:   if (subtarget && REGNO (subtarget) < FIRST_PSEUDO_REGISTER)
        !          2841:     subtarget = 0;
        !          2842:   /* Avoid subtargets inside loops,
        !          2843:      since they hide some invariant expressions.  */
        !          2844:   if (preserve_subexpressions_p ())
        !          2845:     subtarget = 0;
        !          2846: 
        !          2847:   if (ignore) target = 0, original_target = 0;
        !          2848: 
        !          2849:   /* If will do cse, generate all results into pseudo registers
        !          2850:      since 1) that allows cse to find more things
        !          2851:      and 2) otherwise cse could produce an insn the machine
        !          2852:      cannot support.  */
        !          2853: 
        !          2854:   if (! cse_not_expected && mode != BLKmode && target
        !          2855:       && (GET_CODE (target) != REG || REGNO (target) < FIRST_PSEUDO_REGISTER))
        !          2856:     target = subtarget;
        !          2857: 
        !          2858:   /* Ensure we reference a volatile object even if value is ignored.  */
        !          2859:   if (ignore && TREE_THIS_VOLATILE (exp)
        !          2860:       && mode != VOIDmode && mode != BLKmode)
        !          2861:     {
        !          2862:       target = gen_reg_rtx (mode);
        !          2863:       temp = expand_expr (exp, target, VOIDmode, modifier);
        !          2864:       if (temp != target)
        !          2865:        emit_move_insn (target, temp);
        !          2866:       return target;
        !          2867:     }
        !          2868: 
        !          2869:   switch (code)
        !          2870:     {
        !          2871:     case LABEL_DECL:
        !          2872:       if (modifier == EXPAND_INITIALIZER)
        !          2873:        forced_labels = gen_rtx (EXPR_LIST, VOIDmode,
        !          2874:                                 label_rtx (exp), forced_labels);
        !          2875:       return gen_rtx (MEM, FUNCTION_MODE,
        !          2876:                      gen_rtx (LABEL_REF, Pmode, label_rtx (exp)));
        !          2877: 
        !          2878:     case PARM_DECL:
        !          2879:       if (DECL_RTL (exp) == 0)
        !          2880:        {
        !          2881:          error_with_decl (exp, "prior parameter's size depends on `%s'");
        !          2882:          return const0_rtx;
        !          2883:        }
        !          2884: 
        !          2885:     case FUNCTION_DECL:
        !          2886:     case VAR_DECL:
        !          2887:     case RESULT_DECL:
        !          2888:       if (DECL_RTL (exp) == 0)
        !          2889:        abort ();
        !          2890:       /* Ensure variable marked as used
        !          2891:         even if it doesn't go through a parser.  */
        !          2892:       TREE_USED (exp) = 1;
        !          2893:       /* Handle variables inherited from containing functions.  */
        !          2894:       context = decl_function_context (exp);
        !          2895: 
        !          2896:       /* We treat inline_function_decl as an alias for the current function
        !          2897:         because that is the inline function whose vars, types, etc.
        !          2898:         are being merged into the current function.
        !          2899:         See expand_inline_function.  */
        !          2900:       if (context != 0 && context != current_function_decl
        !          2901:          && context != inline_function_decl
        !          2902:          /* If var is static, we don't need a static chain to access it.  */
        !          2903:          && ! (GET_CODE (DECL_RTL (exp)) == MEM
        !          2904:                && CONSTANT_P (XEXP (DECL_RTL (exp), 0))))
        !          2905:        {
        !          2906:          rtx addr;
        !          2907: 
        !          2908:          /* Mark as non-local and addressable.  */
        !          2909:          TREE_NONLOCAL (exp) = 1;
        !          2910:          mark_addressable (exp);
        !          2911:          if (GET_CODE (DECL_RTL (exp)) != MEM)
        !          2912:            abort ();
        !          2913:          addr = XEXP (DECL_RTL (exp), 0);
        !          2914:          if (GET_CODE (addr) == MEM)
        !          2915:            addr = gen_rtx (MEM, Pmode, fix_lexical_addr (XEXP (addr, 0), exp));
        !          2916:          else
        !          2917:            addr = fix_lexical_addr (addr, exp);
        !          2918:          return change_address (DECL_RTL (exp), mode, addr);
        !          2919:        }
        !          2920:       /* This is the case of an array whose size is to be determined
        !          2921:         from its initializer, while the initializer is still being parsed.
        !          2922:         See expand_decl.  */
        !          2923:       if (GET_CODE (DECL_RTL (exp)) == MEM
        !          2924:          && GET_CODE (XEXP (DECL_RTL (exp), 0)) == REG)
        !          2925:        return change_address (DECL_RTL (exp), GET_MODE (DECL_RTL (exp)),
        !          2926:                               XEXP (DECL_RTL (exp), 0));
        !          2927:       if (GET_CODE (DECL_RTL (exp)) == MEM
        !          2928:          && modifier != EXPAND_CONST_ADDRESS
        !          2929:          && modifier != EXPAND_SUM
        !          2930:          && modifier != EXPAND_INITIALIZER)
        !          2931:        {
        !          2932:          /* DECL_RTL probably contains a constant address.
        !          2933:             On RISC machines where a constant address isn't valid,
        !          2934:             make some insns to get that address into a register.  */
        !          2935:          if (!memory_address_p (DECL_MODE (exp), XEXP (DECL_RTL (exp), 0))
        !          2936:              || (flag_force_addr
        !          2937:                  && CONSTANT_ADDRESS_P (XEXP (DECL_RTL (exp), 0))))
        !          2938:            return change_address (DECL_RTL (exp), VOIDmode,
        !          2939:                                   copy_rtx (XEXP (DECL_RTL (exp), 0)));
        !          2940:        }
        !          2941:       return DECL_RTL (exp);
        !          2942: 
        !          2943:     case INTEGER_CST:
        !          2944:       return immed_double_const (TREE_INT_CST_LOW (exp),
        !          2945:                                 TREE_INT_CST_HIGH (exp),
        !          2946:                                 mode);
        !          2947: 
        !          2948:     case CONST_DECL:
        !          2949:       return expand_expr (DECL_INITIAL (exp), target, VOIDmode, 0);
        !          2950: 
        !          2951:     case REAL_CST:
        !          2952:       /* If optimized, generate immediate CONST_DOUBLE
        !          2953:         which will be turned into memory by reload if necessary. 
        !          2954:      
        !          2955:         We used to force a register so that loop.c could see it.  But
        !          2956:         this does not allow gen_* patterns to perform optimizations with
        !          2957:         the constants.  It also produces two insns in cases like "x = 1.0;".
        !          2958:         On most machines, floating-point constants are not permitted in
        !          2959:         many insns, so we'd end up copying it to a register in any case.
        !          2960: 
        !          2961:         Now, we do the copying in expand_binop, if appropriate.  */
        !          2962:       return immed_real_const (exp);
        !          2963: 
        !          2964:     case COMPLEX_CST:
        !          2965:     case STRING_CST:
        !          2966:       if (! TREE_CST_RTL (exp))
        !          2967:        output_constant_def (exp);
        !          2968: 
        !          2969:       /* TREE_CST_RTL probably contains a constant address.
        !          2970:         On RISC machines where a constant address isn't valid,
        !          2971:         make some insns to get that address into a register.  */
        !          2972:       if (GET_CODE (TREE_CST_RTL (exp)) == MEM
        !          2973:          && modifier != EXPAND_CONST_ADDRESS
        !          2974:          && modifier != EXPAND_INITIALIZER
        !          2975:          && modifier != EXPAND_SUM
        !          2976:          && !memory_address_p (mode, XEXP (TREE_CST_RTL (exp), 0)))
        !          2977:        return change_address (TREE_CST_RTL (exp), VOIDmode,
        !          2978:                               copy_rtx (XEXP (TREE_CST_RTL (exp), 0)));
        !          2979:       return TREE_CST_RTL (exp);
        !          2980: 
        !          2981:     case SAVE_EXPR:
        !          2982:       context = decl_function_context (exp);
        !          2983:       /* We treat inline_function_decl as an alias for the current function
        !          2984:         because that is the inline function whose vars, types, etc.
        !          2985:         are being merged into the current function.
        !          2986:         See expand_inline_function.  */
        !          2987:       if (context == current_function_decl || context == inline_function_decl)
        !          2988:        context = 0;
        !          2989: 
        !          2990:       /* If this is non-local, handle it.  */
        !          2991:       if (context)
        !          2992:        {
        !          2993:          temp = SAVE_EXPR_RTL (exp);
        !          2994:          if (temp && GET_CODE (temp) == REG)
        !          2995:            {
        !          2996:              put_var_into_stack (exp);
        !          2997:              temp = SAVE_EXPR_RTL (exp);
        !          2998:            }
        !          2999:          if (temp == 0 || GET_CODE (temp) != MEM)
        !          3000:            abort ();
        !          3001:          return change_address (temp, mode,
        !          3002:                                 fix_lexical_addr (XEXP (temp, 0), exp));
        !          3003:        }
        !          3004:       if (SAVE_EXPR_RTL (exp) == 0)
        !          3005:        {
        !          3006:          if (mode == BLKmode)
        !          3007:            temp
        !          3008:              = assign_stack_temp (mode,
        !          3009:                                   int_size_in_bytes (TREE_TYPE (exp)), 0);
        !          3010:          else
        !          3011:            temp = gen_reg_rtx (mode);
        !          3012:          SAVE_EXPR_RTL (exp) = temp;
        !          3013:          store_expr (TREE_OPERAND (exp, 0), temp, 0);
        !          3014:          if (!optimize && GET_CODE (temp) == REG)
        !          3015:            save_expr_regs = gen_rtx (EXPR_LIST, VOIDmode, temp,
        !          3016:                                      save_expr_regs);
        !          3017:        }
        !          3018:       return SAVE_EXPR_RTL (exp);
        !          3019: 
        !          3020:     case EXIT_EXPR:
        !          3021:       /* Exit the current loop if the body-expression is true.  */
        !          3022:       {
        !          3023:        rtx label = gen_label_rtx ();
        !          3024:        do_jump (TREE_OPERAND (exp, 0), label, 0);
        !          3025:        expand_exit_loop (0);
        !          3026:        emit_label (label);
        !          3027:       }
        !          3028:       return const0_rtx;
        !          3029: 
        !          3030:     case LOOP_EXPR:
        !          3031:       expand_start_loop (1);
        !          3032:       expand_expr_stmt (TREE_OPERAND (exp, 0));
        !          3033:       expand_end_loop ();
        !          3034: 
        !          3035:       return const0_rtx;
        !          3036: 
        !          3037:     case BIND_EXPR:
        !          3038:       {
        !          3039:        tree vars = TREE_OPERAND (exp, 0);
        !          3040:        int vars_need_expansion = 0;
        !          3041: 
        !          3042:        /* Need to open a binding contour here because
        !          3043:           if there are any cleanups they most be contained here.  */
        !          3044:        expand_start_bindings (0);
        !          3045: 
        !          3046:        /* Mark the corresponding BLOCK for output.  */
        !          3047:        if (TREE_OPERAND (exp, 2) != 0)
        !          3048:          TREE_USED (TREE_OPERAND (exp, 2)) = 1;
        !          3049: 
        !          3050:        /* If VARS have not yet been expanded, expand them now.  */
        !          3051:        while (vars)
        !          3052:          {
        !          3053:            if (DECL_RTL (vars) == 0)
        !          3054:              {
        !          3055:                vars_need_expansion = 1;
        !          3056:                expand_decl (vars);
        !          3057:              }
        !          3058:            expand_decl_init (vars);
        !          3059:            vars = TREE_CHAIN (vars);
        !          3060:          }
        !          3061: 
        !          3062:        temp = expand_expr (TREE_OPERAND (exp, 1), target, tmode, modifier);
        !          3063: 
        !          3064:        expand_end_bindings (TREE_OPERAND (exp, 0), 0, 0);
        !          3065: 
        !          3066:        return temp;
        !          3067:       }
        !          3068: 
        !          3069:     case RTL_EXPR:
        !          3070:       if (RTL_EXPR_SEQUENCE (exp) == const0_rtx)
        !          3071:        abort ();
        !          3072:       emit_insns (RTL_EXPR_SEQUENCE (exp));
        !          3073:       RTL_EXPR_SEQUENCE (exp) = const0_rtx;
        !          3074:       return RTL_EXPR_RTL (exp);
        !          3075: 
        !          3076:     case CONSTRUCTOR:
        !          3077:       /* All elts simple constants => refer to a constant in memory.  */
        !          3078:       if (TREE_STATIC (exp))
        !          3079:        /* For aggregate types with non-BLKmode modes,
        !          3080:           this should ideally construct a CONST_INT.  */
        !          3081:        {
        !          3082:          rtx constructor = output_constant_def (exp);
        !          3083:          if (! memory_address_p (GET_MODE (constructor),
        !          3084:                                  XEXP (constructor, 0)))
        !          3085:            constructor = change_address (constructor, VOIDmode,
        !          3086:                                          XEXP (constructor, 0));
        !          3087:          return constructor;
        !          3088:        }
        !          3089: 
        !          3090:       if (ignore)
        !          3091:        {
        !          3092:          tree elt;
        !          3093:          for (elt = CONSTRUCTOR_ELTS (exp); elt; elt = TREE_CHAIN (elt))
        !          3094:            expand_expr (TREE_VALUE (elt), const0_rtx, VOIDmode, 0);
        !          3095:          return const0_rtx;
        !          3096:        }
        !          3097:       else
        !          3098:        {
        !          3099:          if (target == 0 || ! safe_from_p (target, exp))
        !          3100:            {
        !          3101:              if (mode != BLKmode && ! TREE_ADDRESSABLE (exp))
        !          3102:                target = gen_reg_rtx (mode);
        !          3103:              else
        !          3104:                {
        !          3105:                  rtx safe_target = assign_stack_temp (mode, int_size_in_bytes (type), 0);
        !          3106:                  if (target)
        !          3107:                    MEM_IN_STRUCT_P (safe_target) = MEM_IN_STRUCT_P (target);
        !          3108:                  target = safe_target;
        !          3109:                }
        !          3110:            }
        !          3111:          store_constructor (exp, target);
        !          3112:          return target;
        !          3113:        }
        !          3114: 
        !          3115:     case INDIRECT_REF:
        !          3116:       {
        !          3117:        tree exp1 = TREE_OPERAND (exp, 0);
        !          3118:        tree exp2;
        !          3119: 
        !          3120:        /* A SAVE_EXPR as the address in an INDIRECT_EXPR is generated
        !          3121:           for  *PTR += ANYTHING  where PTR is put inside the SAVE_EXPR.
        !          3122:           This code has the same general effect as simply doing
        !          3123:           expand_expr on the save expr, except that the expression PTR
        !          3124:           is computed for use as a memory address.  This means different
        !          3125:           code, suitable for indexing, may be generated.  */
        !          3126:        if (TREE_CODE (exp1) == SAVE_EXPR
        !          3127:            && SAVE_EXPR_RTL (exp1) == 0
        !          3128:            && TREE_CODE (exp2 = TREE_OPERAND (exp1, 0)) != ERROR_MARK
        !          3129:            && TYPE_MODE (TREE_TYPE (exp1)) == Pmode
        !          3130:            && TYPE_MODE (TREE_TYPE (exp2)) == Pmode)
        !          3131:          {
        !          3132:            temp = expand_expr (TREE_OPERAND (exp1, 0), 0, VOIDmode, EXPAND_SUM);
        !          3133:            op0 = memory_address (mode, temp);
        !          3134:            op0 = copy_all_regs (op0);
        !          3135:            SAVE_EXPR_RTL (exp1) = op0;
        !          3136:          }
        !          3137:        else
        !          3138:          {
        !          3139:            op0 = expand_expr (exp1, 0, VOIDmode, EXPAND_SUM);
        !          3140:            op0 = memory_address (mode, op0);
        !          3141:          }
        !          3142:       }
        !          3143:       temp = gen_rtx (MEM, mode, op0);
        !          3144:       /* If address was computed by addition,
        !          3145:         mark this as an element of an aggregate.  */
        !          3146:       if (TREE_CODE (TREE_OPERAND (exp, 0)) == PLUS_EXPR
        !          3147:          || (TREE_CODE (TREE_OPERAND (exp, 0)) == SAVE_EXPR
        !          3148:              && TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) == PLUS_EXPR)
        !          3149:          || TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE
        !          3150:          || TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE
        !          3151:          || TREE_CODE (TREE_TYPE (exp)) == UNION_TYPE)
        !          3152:        MEM_IN_STRUCT_P (temp) = 1;
        !          3153:       MEM_VOLATILE_P (temp) = TREE_THIS_VOLATILE (exp) || flag_volatile;
        !          3154: #if 0 /* It is incorrectto set RTX_UNCHANGING_P here, because the fact that
        !          3155:         a location is accessed through a pointer to const does not mean
        !          3156:         that the value there can never change.  */
        !          3157:       RTX_UNCHANGING_P (temp) = TREE_READONLY (exp);
        !          3158: #endif
        !          3159:       return temp;
        !          3160: 
        !          3161:     case ARRAY_REF:
        !          3162:       if (TREE_CODE (TREE_OPERAND (exp, 1)) != INTEGER_CST
        !          3163:          || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
        !          3164:        {
        !          3165:          /* Nonconstant array index or nonconstant element size.
        !          3166:             Generate the tree for *(&array+index) and expand that,
        !          3167:             except do it in a language-independent way
        !          3168:             and don't complain about non-lvalue arrays.
        !          3169:             `mark_addressable' should already have been called
        !          3170:             for any array for which this case will be reached.  */
        !          3171: 
        !          3172:          /* Don't forget the const or volatile flag from the array element. */
        !          3173:          tree variant_type = build_type_variant (type,
        !          3174:                                                  TREE_READONLY (exp),
        !          3175:                                                  TREE_THIS_VOLATILE (exp));
        !          3176:          tree array_adr = build1 (ADDR_EXPR, build_pointer_type (variant_type),
        !          3177:                                   TREE_OPERAND (exp, 0));
        !          3178:          tree index = TREE_OPERAND (exp, 1);
        !          3179:          tree elt;
        !          3180: 
        !          3181:          /* Convert the integer argument to a type the same size as a pointer
        !          3182:             so the multiply won't overflow spuriously.  */
        !          3183:          if (TYPE_PRECISION (TREE_TYPE (index)) != POINTER_SIZE)
        !          3184:            index = convert (type_for_size (POINTER_SIZE, 0), index);
        !          3185: 
        !          3186:          /* Don't think the address has side effects
        !          3187:             just because the array does.
        !          3188:             (In some cases the address might have side effects,
        !          3189:             and we fail to record that fact here.  However, it should not
        !          3190:             matter, since expand_expr should not care.)  */
        !          3191:          TREE_SIDE_EFFECTS (array_adr) = 0;
        !          3192: 
        !          3193:          elt = build1 (INDIRECT_REF, type,
        !          3194:                        fold (build (PLUS_EXPR, TYPE_POINTER_TO (variant_type),
        !          3195:                                     array_adr,
        !          3196:                                     fold (build (MULT_EXPR,
        !          3197:                                                  TYPE_POINTER_TO (variant_type),
        !          3198:                                                  index, size_in_bytes (type))))));
        !          3199: 
        !          3200:          /* Volatility, etc., of new expression is same as old expression.  */
        !          3201:          TREE_SIDE_EFFECTS (elt) = TREE_SIDE_EFFECTS (exp);
        !          3202:          TREE_THIS_VOLATILE (elt) = TREE_THIS_VOLATILE (exp);
        !          3203:          TREE_READONLY (elt) = TREE_READONLY (exp);
        !          3204: 
        !          3205:          return expand_expr (elt, target, tmode, modifier);
        !          3206:        }
        !          3207: 
        !          3208:       /* Fold an expression like: "foo"[2].
        !          3209:         This is not done in fold so it won't happen inside &.  */
        !          3210:       {
        !          3211:        int i;
        !          3212:        tree arg0 = TREE_OPERAND (exp, 0);
        !          3213:        tree arg1 = TREE_OPERAND (exp, 1);
        !          3214: 
        !          3215:        if (TREE_CODE (arg0) == STRING_CST
        !          3216:            && TREE_CODE (arg1) == INTEGER_CST
        !          3217:            && !TREE_INT_CST_HIGH (arg1)
        !          3218:            && (i = TREE_INT_CST_LOW (arg1)) < TREE_STRING_LENGTH (arg0))
        !          3219:          {
        !          3220:            if (TREE_TYPE (TREE_TYPE (arg0)) == integer_type_node)
        !          3221:              {
        !          3222:                exp = build_int_2 (((int *)TREE_STRING_POINTER (arg0))[i], 0);
        !          3223:                TREE_TYPE (exp) = integer_type_node;
        !          3224:                return expand_expr (exp, target, tmode, modifier);
        !          3225:              }
        !          3226:            if (TREE_TYPE (TREE_TYPE (arg0)) == char_type_node)
        !          3227:              {
        !          3228:                exp = build_int_2 (TREE_STRING_POINTER (arg0)[i], 0);
        !          3229:                TREE_TYPE (exp) = integer_type_node;
        !          3230:                return expand_expr (convert (TREE_TYPE (TREE_TYPE (arg0)), exp), target, tmode, modifier);
        !          3231:              }
        !          3232:          }
        !          3233:       }
        !          3234: 
        !          3235:       /* If this is a constant index into a constant array,
        !          3236:         just get the value from the array.  */
        !          3237:       if (TREE_READONLY (TREE_OPERAND (exp, 0))
        !          3238:          && ! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 0))
        !          3239:          && TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == ARRAY_TYPE
        !          3240:          && TREE_CODE (TREE_OPERAND (exp, 0)) == VAR_DECL
        !          3241:          && DECL_INITIAL (TREE_OPERAND (exp, 0))
        !          3242:          && TREE_CODE (DECL_INITIAL (TREE_OPERAND (exp, 0))) != ERROR_MARK)
        !          3243:        {
        !          3244:          tree index = fold (TREE_OPERAND (exp, 1));
        !          3245:          if (TREE_CODE (index) == INTEGER_CST)
        !          3246:            {
        !          3247:              int i = TREE_INT_CST_LOW (index);
        !          3248:              tree init = CONSTRUCTOR_ELTS (DECL_INITIAL (TREE_OPERAND (exp, 0)));
        !          3249: 
        !          3250:              while (init && i--)
        !          3251:                init = TREE_CHAIN (init);
        !          3252:              if (init)
        !          3253:                return expand_expr (fold (TREE_VALUE (init)), target, tmode, modifier);
        !          3254:            }
        !          3255:        }
        !          3256:       /* Treat array-ref with constant index as a component-ref.  */
        !          3257: 
        !          3258:     case COMPONENT_REF:
        !          3259:     case BIT_FIELD_REF:
        !          3260:       {
        !          3261:        enum machine_mode mode1;
        !          3262:        int bitsize;
        !          3263:        int bitpos;
        !          3264:        int volatilep = 0;
        !          3265:        tree tem = get_inner_reference (exp, &bitsize, &bitpos,
        !          3266:                                        &mode1, &unsignedp, &volatilep);
        !          3267: 
        !          3268:        /* In some cases, we will be offsetting OP0's address by a constant.
        !          3269:           So get it as a sum, if possible.  If we will be using it
        !          3270:           directly in an insn, we validate it.  */
        !          3271:        op0 = expand_expr (tem, 0, VOIDmode, EXPAND_SUM);
        !          3272: 
        !          3273:        /* Don't forget about volatility even if this is a bitfield.  */
        !          3274:        if (GET_CODE (op0) == MEM && volatilep && ! MEM_VOLATILE_P (op0))
        !          3275:          {
        !          3276:            op0 = copy_rtx (op0);
        !          3277:            MEM_VOLATILE_P (op0) = 1;
        !          3278:          }
        !          3279: 
        !          3280:        if (mode1 == VOIDmode
        !          3281:            || GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG)
        !          3282:          {
        !          3283:            /* In cases where an aligned union has an unaligned object
        !          3284:               as a field, we might be extracting a BLKmode value from
        !          3285:               an integer-mode (e.g., SImode) object.  Handle this case
        !          3286:               by doing the extract into an object as wide as the field
        !          3287:               (which we know to be the width of a basic mode), then
        !          3288:               storing into memory, and changing the mode to BLKmode.  */
        !          3289:            enum machine_mode ext_mode = mode;
        !          3290: 
        !          3291:            if (ext_mode == BLKmode)
        !          3292:              ext_mode = mode_for_size (bitsize, MODE_INT, 1);
        !          3293: 
        !          3294:            if (ext_mode == BLKmode)
        !          3295:              abort ();
        !          3296: 
        !          3297:            op0 = extract_bit_field (validize_mem (op0), bitsize, bitpos,
        !          3298:                                     unsignedp, target, ext_mode, ext_mode,
        !          3299:                                     TYPE_ALIGN (TREE_TYPE (tem)) / BITS_PER_UNIT,
        !          3300:                                     int_size_in_bytes (TREE_TYPE (tem)));
        !          3301:            if (mode == BLKmode)
        !          3302:              {
        !          3303:                rtx new = assign_stack_temp (ext_mode,
        !          3304:                                             bitsize / BITS_PER_UNIT, 0);
        !          3305: 
        !          3306:                emit_move_insn (new, op0);
        !          3307:                op0 = copy_rtx (new);
        !          3308:                PUT_MODE (op0, BLKmode);
        !          3309:              }
        !          3310: 
        !          3311:            return op0;
        !          3312:          }
        !          3313: 
        !          3314:        /* Get a reference to just this component.  */
        !          3315:        if (modifier == EXPAND_CONST_ADDRESS
        !          3316:            || modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER)
        !          3317:          op0 = gen_rtx (MEM, mode1, plus_constant (XEXP (op0, 0),
        !          3318:                                                    (bitpos / BITS_PER_UNIT)));
        !          3319:        else
        !          3320:          op0 = change_address (op0, mode1,
        !          3321:                                plus_constant (XEXP (op0, 0),
        !          3322:                                               (bitpos / BITS_PER_UNIT)));
        !          3323:        MEM_IN_STRUCT_P (op0) = 1;
        !          3324:        MEM_VOLATILE_P (op0) |= volatilep;
        !          3325:        if (mode == mode1 || mode1 == BLKmode || mode1 == tmode)
        !          3326:          return op0;
        !          3327:        if (target == 0)
        !          3328:          target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
        !          3329:        convert_move (target, op0, unsignedp);
        !          3330:        return target;
        !          3331:       }
        !          3332: 
        !          3333:     case OFFSET_REF:
        !          3334:       {
        !          3335:        tree base = build_unary_op (ADDR_EXPR, TREE_OPERAND (exp, 0), 0);
        !          3336:        tree addr = build (PLUS_EXPR, type, base, TREE_OPERAND (exp, 1));
        !          3337:        op0 = expand_expr (addr, 0, VOIDmode, EXPAND_SUM);
        !          3338:        temp = gen_rtx (MEM, mode, memory_address (mode, op0));
        !          3339:        MEM_IN_STRUCT_P (temp) = 1;
        !          3340:        MEM_VOLATILE_P (temp) = TREE_THIS_VOLATILE (exp) || flag_volatile;
        !          3341: #if 0 /* It is incorrectto set RTX_UNCHANGING_P here, because the fact that
        !          3342:         a location is accessed through a pointer to const does not mean
        !          3343:         that the value there can never change.  */
        !          3344:        RTX_UNCHANGING_P (temp) = TREE_READONLY (exp);
        !          3345: #endif
        !          3346:        return temp;
        !          3347:       }
        !          3348: 
        !          3349:       /* Intended for a reference to a buffer of a file-object in Pascal.
        !          3350:         But it's not certain that a special tree code will really be
        !          3351:         necessary for these.  INDIRECT_REF might work for them.  */
        !          3352:     case BUFFER_REF:
        !          3353:       abort ();
        !          3354: 
        !          3355:     case WITH_CLEANUP_EXPR:
        !          3356:       if (RTL_EXPR_RTL (exp) == 0)
        !          3357:        {
        !          3358:          RTL_EXPR_RTL (exp)
        !          3359:            = expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
        !          3360:          cleanups_this_call = tree_cons (0, TREE_OPERAND (exp, 2), cleanups_this_call);
        !          3361:          /* That's it for this cleanup.  */
        !          3362:          TREE_OPERAND (exp, 2) = 0;
        !          3363:        }
        !          3364:       return RTL_EXPR_RTL (exp);
        !          3365: 
        !          3366:     case CALL_EXPR:
        !          3367:       /* Check for a built-in function.  */
        !          3368:       if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
        !          3369:          && TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) == FUNCTION_DECL
        !          3370:          && DECL_BUILT_IN (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
        !          3371:        return expand_builtin (exp, target, subtarget, tmode, ignore);
        !          3372:       /* If this call was expanded already by preexpand_calls,
        !          3373:         just return the result we got.  */
        !          3374:       if (CALL_EXPR_RTL (exp) != 0)
        !          3375:        return CALL_EXPR_RTL (exp);
        !          3376:       return expand_call (exp, target, ignore, modifier);
        !          3377: 
        !          3378:     case NON_LVALUE_EXPR:
        !          3379:     case NOP_EXPR:
        !          3380:     case CONVERT_EXPR:
        !          3381:     case REFERENCE_EXPR:
        !          3382:       if (TREE_CODE (type) == VOID_TYPE || ignore)
        !          3383:        {
        !          3384:          expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, modifier);
        !          3385:          return const0_rtx;
        !          3386:        }
        !          3387:       if (mode == TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
        !          3388:        return expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, modifier);
        !          3389:       if (TREE_CODE (type) == UNION_TYPE)
        !          3390:        {
        !          3391:          tree valtype = TREE_TYPE (TREE_OPERAND (exp, 0));
        !          3392:          if (target == 0)
        !          3393:            {
        !          3394:              if (mode == BLKmode)
        !          3395:                {
        !          3396:                  if (TYPE_SIZE (type) == 0
        !          3397:                      || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
        !          3398:                    abort ();
        !          3399:                  target = assign_stack_temp (BLKmode,
        !          3400:                                              (TREE_INT_CST_LOW (TYPE_SIZE (type))
        !          3401:                                               + BITS_PER_UNIT - 1)
        !          3402:                                              / BITS_PER_UNIT, 0);
        !          3403:                }
        !          3404:              else
        !          3405:                target = gen_reg_rtx (mode);
        !          3406:            }
        !          3407:          if (GET_CODE (target) == MEM)
        !          3408:            /* Store data into beginning of memory target.  */
        !          3409:            store_expr (TREE_OPERAND (exp, 0),
        !          3410:                        change_address (target, TYPE_MODE (valtype), 0), 0);
        !          3411:          else if (GET_CODE (target) == REG)
        !          3412:            /* Store this field into a union of the proper type.  */
        !          3413:            store_field (target, GET_MODE_BITSIZE (TYPE_MODE (valtype)), 0,
        !          3414:                         TYPE_MODE (valtype), TREE_OPERAND (exp, 0),
        !          3415:                         VOIDmode, 0, 1,
        !          3416:                         int_size_in_bytes (TREE_TYPE (TREE_OPERAND (exp, 0))));
        !          3417:          else
        !          3418:            abort ();
        !          3419: 
        !          3420:          /* Return the entire union.  */
        !          3421:          return target;
        !          3422:        }
        !          3423:       op0 = expand_expr (TREE_OPERAND (exp, 0), 0, mode, 0);
        !          3424:       if (GET_MODE (op0) == mode || GET_MODE (op0) == VOIDmode)
        !          3425:        return op0;
        !          3426:       if (flag_force_mem && GET_CODE (op0) == MEM)
        !          3427:        op0 = copy_to_reg (op0);
        !          3428: 
        !          3429:       if (target == 0)
        !          3430:        return convert_to_mode (mode, op0, TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
        !          3431:       else
        !          3432:        convert_move (target, op0, TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
        !          3433:       return target;
        !          3434: 
        !          3435:     case PLUS_EXPR:
        !          3436:       /* We come here from MINUS_EXPR when the second operand is a constant. */
        !          3437:     plus_expr:
        !          3438:       this_optab = add_optab;
        !          3439: 
        !          3440:       /* If we are adding a constant, an RTL_EXPR that is sp, fp, or ap, and
        !          3441:         something else, make sure we add the register to the constant and
        !          3442:         then to the other thing.  This case can occur during strength
        !          3443:         reduction and doing it this way will produce better code if the
        !          3444:         frame pointer or argument pointer is eliminated.
        !          3445: 
        !          3446:         fold-const.c will ensure that the constant is always in the inner
        !          3447:         PLUS_EXPR, so the only case we need to do anything about is if
        !          3448:         sp, ap, or fp is our second argument, in which case we must swap
        !          3449:         the innermost first argument and our second argument.  */
        !          3450: 
        !          3451:       if (TREE_CODE (TREE_OPERAND (exp, 0)) == PLUS_EXPR
        !          3452:          && TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 1)) == INTEGER_CST
        !          3453:          && TREE_CODE (TREE_OPERAND (exp, 1)) == RTL_EXPR
        !          3454:          && (RTL_EXPR_RTL (TREE_OPERAND (exp, 1)) == frame_pointer_rtx
        !          3455:              || RTL_EXPR_RTL (TREE_OPERAND (exp, 1)) == stack_pointer_rtx
        !          3456:              || RTL_EXPR_RTL (TREE_OPERAND (exp, 1)) == arg_pointer_rtx))
        !          3457:        {
        !          3458:          tree t = TREE_OPERAND (exp, 1);
        !          3459: 
        !          3460:          TREE_OPERAND (exp, 1) = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
        !          3461:          TREE_OPERAND (TREE_OPERAND (exp, 0), 0) = t;
        !          3462:        }
        !          3463: 
        !          3464:       /* If the result is to be Pmode and we are adding an integer to
        !          3465:         something, we might be forming a constant.  So try to use
        !          3466:         plus_constant.  If it produces a sum and we can't accept it,
        !          3467:         use force_operand.  This allows P = &ARR[const] to generate
        !          3468:         efficient code on machines where a SYMBOL_REF is not a valid
        !          3469:         address.
        !          3470: 
        !          3471:         If this is an EXPAND_SUM call, always return the sum.  */
        !          3472:       if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST
        !          3473:          && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_INT
        !          3474:          && (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER
        !          3475:              || mode == Pmode))
        !          3476:        {
        !          3477:          op1 = expand_expr (TREE_OPERAND (exp, 1), subtarget, VOIDmode,
        !          3478:                             EXPAND_SUM);
        !          3479:          op1 = plus_constant (op1, TREE_INT_CST_LOW (TREE_OPERAND (exp, 0)));
        !          3480:          if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
        !          3481:            op1 = force_operand (op1, target);
        !          3482:          return op1;
        !          3483:        }
        !          3484: 
        !          3485:       else if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
        !          3486:               && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_INT
        !          3487:               && (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER
        !          3488:                   || mode == Pmode))
        !          3489:        {
        !          3490:          op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode,
        !          3491:                             EXPAND_SUM);
        !          3492:          op0 = plus_constant (op0, TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)));
        !          3493:          if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
        !          3494:            op0 = force_operand (op0, target);
        !          3495:          return op0;
        !          3496:        }
        !          3497: 
        !          3498:       /* No sense saving up arithmetic to be done
        !          3499:         if it's all in the wrong mode to form part of an address.
        !          3500:         And force_operand won't know whether to sign-extend or
        !          3501:         zero-extend.  */
        !          3502:       if ((modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
        !          3503:          || mode != Pmode) goto binop;
        !          3504: 
        !          3505:       preexpand_calls (exp);
        !          3506:       if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1)))
        !          3507:        subtarget = 0;
        !          3508: 
        !          3509:       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, modifier);
        !          3510:       op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, modifier);
        !          3511:       /* Put a sum last, to simplify what follows.  */
        !          3512: #ifdef OLD_INDEXING
        !          3513:       if (GET_CODE (op1) == MULT)
        !          3514:        {
        !          3515:          temp = op0;
        !          3516:          op0 = op1;
        !          3517:          op1 = temp;
        !          3518:        }
        !          3519: #endif
        !          3520: #ifndef OLD_INDEXING
        !          3521:       /* Make sure any term that's a sum with a constant comes last.  */
        !          3522:       if (GET_CODE (op0) == PLUS
        !          3523:          && CONSTANT_P (XEXP (op0, 1)))
        !          3524:        {
        !          3525:          temp = op0;
        !          3526:          op0 = op1;
        !          3527:          op1 = temp;
        !          3528:        }
        !          3529:       /* If adding to a sum including a constant,
        !          3530:         associate it to put the constant outside.  */
        !          3531:       if (GET_CODE (op1) == PLUS
        !          3532:          && CONSTANT_P (XEXP (op1, 1)))
        !          3533:        {
        !          3534:          rtx tem;
        !          3535:          int constant_term = 0;
        !          3536: 
        !          3537:          op0 = gen_rtx (PLUS, mode, XEXP (op1, 0), op0);
        !          3538:          /* Let's also eliminate constants from op0 if possible.  */
        !          3539:          tem = eliminate_constant_term (op0, &constant_term);
        !          3540:          if (GET_CODE (XEXP (op1, 1)) == CONST_INT)
        !          3541:            {
        !          3542:              if (constant_term != 0)
        !          3543:                return plus_constant (tem, INTVAL (XEXP (op1, 1)) + constant_term);
        !          3544:              else
        !          3545:                return plus_constant (op0, INTVAL (XEXP (op1, 1)));
        !          3546:            }
        !          3547:          else
        !          3548:            return gen_rtx (PLUS, mode, op0, XEXP (op1, 1));
        !          3549:        }
        !          3550: #endif
        !          3551:       /* Put a constant term last.  */
        !          3552:       if (CONSTANT_P (op0))
        !          3553:        return gen_rtx (PLUS, mode, op1, op0);
        !          3554:       else
        !          3555:        return gen_rtx (PLUS, mode, op0, op1);
        !          3556: 
        !          3557:     case MINUS_EXPR:
        !          3558:       /* Handle difference of two symbolic constants,
        !          3559:         for the sake of an initializer.  */
        !          3560:       if ((modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER)
        !          3561:          && really_constant_p (TREE_OPERAND (exp, 0))
        !          3562:          && really_constant_p (TREE_OPERAND (exp, 1)))
        !          3563:        {
        !          3564:          rtx op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, modifier);
        !          3565:          rtx op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, modifier);
        !          3566:          return gen_rtx (MINUS, mode, op0, op1);
        !          3567:        }
        !          3568:       /* Convert A - const to A + (-const).  */
        !          3569:       if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
        !          3570:        {
        !          3571:          exp = build (PLUS_EXPR, type, TREE_OPERAND (exp, 0),
        !          3572:                       fold (build1 (NEGATE_EXPR, type,
        !          3573:                                     TREE_OPERAND (exp, 1))));
        !          3574:          goto plus_expr;
        !          3575:        }
        !          3576:       this_optab = sub_optab;
        !          3577:       goto binop;
        !          3578: 
        !          3579:     case MULT_EXPR:
        !          3580:       preexpand_calls (exp);
        !          3581:       /* If first operand is constant, swap them.
        !          3582:         Thus the following special case checks need only
        !          3583:         check the second operand.  */
        !          3584:       if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST)
        !          3585:        {
        !          3586:          register tree t1 = TREE_OPERAND (exp, 0);
        !          3587:          TREE_OPERAND (exp, 0) = TREE_OPERAND (exp, 1);
        !          3588:          TREE_OPERAND (exp, 1) = t1;
        !          3589:        }
        !          3590: 
        !          3591:       /* Attempt to return something suitable for generating an
        !          3592:         indexed address, for machines that support that.  */
        !          3593: 
        !          3594:       if (modifier == EXPAND_SUM && mode == Pmode
        !          3595:          && TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
        !          3596:          && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_INT)
        !          3597:        {
        !          3598:          op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, EXPAND_SUM);
        !          3599: 
        !          3600:          /* Apply distributive law if OP0 is x+c.  */
        !          3601:          if (GET_CODE (op0) == PLUS
        !          3602:              && GET_CODE (XEXP (op0, 1)) == CONST_INT)
        !          3603:            return gen_rtx (PLUS, mode,
        !          3604:                            gen_rtx (MULT, mode, XEXP (op0, 0),
        !          3605:                                     gen_rtx (CONST_INT, VOIDmode,
        !          3606:                                              TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)))),
        !          3607:                            gen_rtx (CONST_INT, VOIDmode,
        !          3608:                                     (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1))
        !          3609:                                      * INTVAL (XEXP (op0, 1)))));
        !          3610: 
        !          3611:          if (GET_CODE (op0) != REG)
        !          3612:            op0 = force_operand (op0, 0);
        !          3613:          if (GET_CODE (op0) != REG)
        !          3614:            op0 = copy_to_mode_reg (mode, op0);
        !          3615: 
        !          3616:          return gen_rtx (MULT, mode, op0,
        !          3617:                          gen_rtx (CONST_INT, VOIDmode,
        !          3618:                                   TREE_INT_CST_LOW (TREE_OPERAND (exp, 1))));
        !          3619:        }
        !          3620: 
        !          3621:       if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1)))
        !          3622:        subtarget = 0;
        !          3623: 
        !          3624:       /* Check for multiplying things that have been extended
        !          3625:         from a narrower type.  If this machine supports multiplying
        !          3626:         in that narrower type with a result in the desired type,
        !          3627:         do it that way, and avoid the explicit type-conversion.  */
        !          3628:       if (TREE_CODE (TREE_OPERAND (exp, 0)) == NOP_EXPR
        !          3629:          && TREE_CODE (type) == INTEGER_TYPE
        !          3630:          && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
        !          3631:              < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0))))
        !          3632:          && ((TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
        !          3633:               && int_fits_type_p (TREE_OPERAND (exp, 1),
        !          3634:                                   TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
        !          3635:               /* Don't use a widening multiply if a shift will do.  */
        !          3636:               && ((GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 1))))
        !          3637:                    > HOST_BITS_PER_INT)
        !          3638:                   || exact_log2 (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1))) < 0))
        !          3639:              ||
        !          3640:              (TREE_CODE (TREE_OPERAND (exp, 1)) == NOP_EXPR
        !          3641:               && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 1), 0)))
        !          3642:                   ==
        !          3643:                   TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))))
        !          3644:               /* If both operands are extended, they must either both
        !          3645:                  be zero-extended or both be sign-extended.  */
        !          3646:               && (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 1), 0)))
        !          3647:                   ==
        !          3648:                   TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))))))
        !          3649:        {
        !          3650:          enum machine_mode innermode
        !          3651:            = TYPE_MODE (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)));
        !          3652:          this_optab = (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
        !          3653:                        ? umul_widen_optab : smul_widen_optab);
        !          3654:          if (mode == GET_MODE_WIDER_MODE (innermode)
        !          3655:              && this_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
        !          3656:            {
        !          3657:              op0 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
        !          3658:                                 0, VOIDmode, 0);
        !          3659:              if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
        !          3660:                op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
        !          3661:              else
        !          3662:                op1 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 1), 0),
        !          3663:                                   0, VOIDmode, 0);
        !          3664:              goto binop2;
        !          3665:            }
        !          3666:        }
        !          3667:       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
        !          3668:       op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
        !          3669:       return expand_mult (mode, op0, op1, target, unsignedp);
        !          3670: 
        !          3671:     case TRUNC_DIV_EXPR:
        !          3672:     case FLOOR_DIV_EXPR:
        !          3673:     case CEIL_DIV_EXPR:
        !          3674:     case ROUND_DIV_EXPR:
        !          3675:     case EXACT_DIV_EXPR:
        !          3676:       preexpand_calls (exp);
        !          3677:       if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1)))
        !          3678:        subtarget = 0;
        !          3679:       /* Possible optimization: compute the dividend with EXPAND_SUM
        !          3680:         then if the divisor is constant can optimize the case
        !          3681:         where some terms of the dividend have coeffs divisible by it.  */
        !          3682:       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
        !          3683:       op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
        !          3684:       return expand_divmod (0, code, mode, op0, op1, target, unsignedp);
        !          3685: 
        !          3686:     case RDIV_EXPR:
        !          3687:       this_optab = flodiv_optab;
        !          3688:       goto binop;
        !          3689: 
        !          3690:     case TRUNC_MOD_EXPR:
        !          3691:     case FLOOR_MOD_EXPR:
        !          3692:     case CEIL_MOD_EXPR:
        !          3693:     case ROUND_MOD_EXPR:
        !          3694:       preexpand_calls (exp);
        !          3695:       if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1)))
        !          3696:        subtarget = 0;
        !          3697:       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
        !          3698:       op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
        !          3699:       return expand_divmod (1, code, mode, op0, op1, target, unsignedp);
        !          3700: 
        !          3701:     case FIX_ROUND_EXPR:
        !          3702:     case FIX_FLOOR_EXPR:
        !          3703:     case FIX_CEIL_EXPR:
        !          3704:       abort ();                        /* Not used for C.  */
        !          3705: 
        !          3706:     case FIX_TRUNC_EXPR:
        !          3707:       op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
        !          3708:       if (target == 0)
        !          3709:        target = gen_reg_rtx (mode);
        !          3710:       expand_fix (target, op0, unsignedp);
        !          3711:       return target;
        !          3712: 
        !          3713:     case FLOAT_EXPR:
        !          3714:       op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
        !          3715:       if (target == 0)
        !          3716:        target = gen_reg_rtx (mode);
        !          3717:       /* expand_float can't figure out what to do if FROM has VOIDmode.
        !          3718:         So give it the correct mode.  With -O, cse will optimize this.  */
        !          3719:       if (GET_MODE (op0) == VOIDmode)
        !          3720:        op0 = copy_to_mode_reg (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))),
        !          3721:                                op0);
        !          3722:       expand_float (target, op0,
        !          3723:                    TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
        !          3724:       return target;
        !          3725: 
        !          3726:     case NEGATE_EXPR:
        !          3727:       op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0);
        !          3728:       temp = expand_unop (mode, neg_optab, op0, target, 0);
        !          3729:       if (temp == 0)
        !          3730:        abort ();
        !          3731:       return temp;
        !          3732: 
        !          3733:     case ABS_EXPR:
        !          3734:       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
        !          3735: 
        !          3736:       /* Unsigned abs is simply the operand.  Testing here means we don't
        !          3737:         risk generating incorrect code below.  */
        !          3738:       if (TREE_UNSIGNED (type))
        !          3739:        return op0;
        !          3740: 
        !          3741:       /* First try to do it with a special abs instruction.  */
        !          3742:       temp = expand_unop (mode, abs_optab, op0, target, 0);
        !          3743:       if (temp != 0)
        !          3744:        return temp;
        !          3745: 
        !          3746:       /* If this machine has expensive jumps, we can do integer absolute
        !          3747:         value of X as (((signed) x >> (W-1)) ^ x) - ((signed) x >> (W-1)),
        !          3748:         where W is the width of MODE.  */
        !          3749: 
        !          3750:       if (GET_MODE_CLASS (mode) == MODE_INT && BRANCH_COST >= 2)
        !          3751:        {
        !          3752:          rtx extended = expand_shift (RSHIFT_EXPR, mode, op0,
        !          3753:                                       size_int (GET_MODE_BITSIZE (mode) - 1),
        !          3754:                                       0, 0);
        !          3755: 
        !          3756:          temp = expand_binop (mode, xor_optab, extended, op0, target, 0,
        !          3757:                               OPTAB_LIB_WIDEN);
        !          3758:          if (temp != 0)
        !          3759:            temp = expand_binop (mode, sub_optab, temp, extended, target, 0,
        !          3760:                                 OPTAB_LIB_WIDEN);
        !          3761: 
        !          3762:          if (temp != 0)
        !          3763:            return temp;
        !          3764:        }
        !          3765: 
        !          3766:       /* If that does not win, use conditional jump and negate.  */
        !          3767:       target = original_target;
        !          3768:       temp = gen_label_rtx ();
        !          3769:       if (target == 0 || ! safe_from_p (target, TREE_OPERAND (exp, 0))
        !          3770:          || (GET_CODE (target) == REG
        !          3771:              && REGNO (target) < FIRST_PSEUDO_REGISTER))
        !          3772:        target = gen_reg_rtx (mode);
        !          3773:       emit_move_insn (target, op0);
        !          3774:       emit_cmp_insn (target,
        !          3775:                     expand_expr (convert (type, integer_zero_node),
        !          3776:                                  0, VOIDmode, 0),
        !          3777:                     GE, 0, mode, 0, 0);
        !          3778:       NO_DEFER_POP;
        !          3779:       emit_jump_insn (gen_bge (temp));
        !          3780:       op0 = expand_unop (mode, neg_optab, target, target, 0);
        !          3781:       if (op0 != target)
        !          3782:        emit_move_insn (target, op0);
        !          3783:       emit_label (temp);
        !          3784:       OK_DEFER_POP;
        !          3785:       return target;
        !          3786: 
        !          3787:     case MAX_EXPR:
        !          3788:     case MIN_EXPR:
        !          3789:       target = original_target;
        !          3790:       if (target == 0 || ! safe_from_p (target, TREE_OPERAND (exp, 1))
        !          3791:          || (GET_CODE (target) == REG
        !          3792:              && REGNO (target) < FIRST_PSEUDO_REGISTER))
        !          3793:        target = gen_reg_rtx (mode);
        !          3794:       op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
        !          3795:       op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0);
        !          3796: 
        !          3797:       /* First try to do it with a special MIN or MAX instruction.
        !          3798:         If that does not win, use a conditional jump to select the proper
        !          3799:         value.  */
        !          3800:       this_optab = (TREE_UNSIGNED (type)
        !          3801:                    ? (code == MIN_EXPR ? umin_optab : umax_optab)
        !          3802:                    : (code == MIN_EXPR ? smin_optab : smax_optab));
        !          3803: 
        !          3804:       temp = expand_binop (mode, this_optab, op0, op1, target, unsignedp,
        !          3805:                           OPTAB_WIDEN);
        !          3806:       if (temp != 0)
        !          3807:        return temp;
        !          3808: 
        !          3809:       if (target != op0)
        !          3810:        emit_move_insn (target, op0);
        !          3811:       op0 = gen_label_rtx ();
        !          3812:       if (code == MAX_EXPR)
        !          3813:        temp = (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 1)))
        !          3814:                ? compare_from_rtx (target, op1, GEU, 1, mode, 0, 0)
        !          3815:                : compare_from_rtx (target, op1, GE, 0, mode, 0, 0));
        !          3816:       else
        !          3817:        temp = (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 1)))
        !          3818:                ? compare_from_rtx (target, op1, LEU, 1, mode, 0, 0)
        !          3819:                : compare_from_rtx (target, op1, LE, 0, mode, 0, 0));
        !          3820:       if (temp == const0_rtx)
        !          3821:        emit_move_insn (target, op1);
        !          3822:       else if (temp != const_true_rtx)
        !          3823:        {
        !          3824:          if (bcc_gen_fctn[(int) GET_CODE (temp)] != 0)
        !          3825:            emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (temp)]) (op0));
        !          3826:          else
        !          3827:            abort ();
        !          3828:          emit_move_insn (target, op1);
        !          3829:        }
        !          3830:       emit_label (op0);
        !          3831:       return target;
        !          3832: 
        !          3833: /* ??? Can optimize when the operand of this is a bitwise operation,
        !          3834:    by using a different bitwise operation.  */
        !          3835:     case BIT_NOT_EXPR:
        !          3836:       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
        !          3837:       temp = expand_unop (mode, one_cmpl_optab, op0, target, 1);
        !          3838:       if (temp == 0)
        !          3839:        abort ();
        !          3840:       return temp;
        !          3841: 
        !          3842:     case FFS_EXPR:
        !          3843:       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
        !          3844:       temp = expand_unop (mode, ffs_optab, op0, target, 1);
        !          3845:       if (temp == 0)
        !          3846:        abort ();
        !          3847:       return temp;
        !          3848: 
        !          3849: /* ??? Can optimize bitwise operations with one arg constant.
        !          3850:    Can optimize (a bitwise1 n) bitwise2 (a bitwise3 b)
        !          3851:    and (a bitwise1 b) bitwise2 b (etc)
        !          3852:    but that is probably not worth while.  */
        !          3853: 
        !          3854: /* BIT_AND_EXPR is for bitwise anding.
        !          3855:    TRUTH_AND_EXPR is for anding two boolean values
        !          3856:    when we want in all cases to compute both of them.
        !          3857:    In general it is fastest to do TRUTH_AND_EXPR by
        !          3858:    computing both operands as actual zero-or-1 values
        !          3859:    and then bitwise anding.  In cases where there cannot
        !          3860:    be any side effects, better code would be made by
        !          3861:    treating TRUTH_AND_EXPR like TRUTH_ANDIF_EXPR;
        !          3862:    but the question is how to recognize those cases.  */
        !          3863: 
        !          3864:     case TRUTH_AND_EXPR:
        !          3865:     case BIT_AND_EXPR:
        !          3866:       this_optab = and_optab;
        !          3867:       goto binop;
        !          3868: 
        !          3869: /* See comment above about TRUTH_AND_EXPR; it applies here too.  */
        !          3870:     case TRUTH_OR_EXPR:
        !          3871:     case BIT_IOR_EXPR:
        !          3872:       this_optab = ior_optab;
        !          3873:       goto binop;
        !          3874: 
        !          3875:     case BIT_XOR_EXPR:
        !          3876:       this_optab = xor_optab;
        !          3877:       goto binop;
        !          3878: 
        !          3879:     case LSHIFT_EXPR:
        !          3880:     case RSHIFT_EXPR:
        !          3881:     case LROTATE_EXPR:
        !          3882:     case RROTATE_EXPR:
        !          3883:       preexpand_calls (exp);
        !          3884:       if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1)))
        !          3885:        subtarget = 0;
        !          3886:       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
        !          3887:       return expand_shift (code, mode, op0, TREE_OPERAND (exp, 1), target,
        !          3888:                           unsignedp);
        !          3889: 
        !          3890: /* Could determine the answer when only additive constants differ.
        !          3891:    Also, the addition of one can be handled by changing the condition.  */
        !          3892:     case LT_EXPR:
        !          3893:     case LE_EXPR:
        !          3894:     case GT_EXPR:
        !          3895:     case GE_EXPR:
        !          3896:     case EQ_EXPR:
        !          3897:     case NE_EXPR:
        !          3898:       preexpand_calls (exp);
        !          3899:       temp = do_store_flag (exp, target, tmode != VOIDmode ? tmode : mode, 0);
        !          3900:       if (temp != 0)
        !          3901:        return temp;
        !          3902:       /* For foo != 0, load foo, and if it is nonzero load 1 instead. */
        !          3903:       if (code == NE_EXPR && integer_zerop (TREE_OPERAND (exp, 1))
        !          3904:          && original_target
        !          3905:          && GET_CODE (original_target) == REG
        !          3906:          && (GET_MODE (original_target)
        !          3907:              == TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
        !          3908:        {
        !          3909:          temp = expand_expr (TREE_OPERAND (exp, 0), original_target, VOIDmode, 0);
        !          3910:          if (temp != original_target)
        !          3911:            temp = copy_to_reg (temp);
        !          3912:          op1 = gen_label_rtx ();
        !          3913:          emit_cmp_insn (temp, const0_rtx, EQ, 0,
        !          3914:                         GET_MODE (temp), unsignedp, 0);
        !          3915:          emit_jump_insn (gen_beq (op1));
        !          3916:          emit_move_insn (temp, const1_rtx);
        !          3917:          emit_label (op1);
        !          3918:          return temp;
        !          3919:        }
        !          3920:       /* If no set-flag instruction, must generate a conditional
        !          3921:         store into a temporary variable.  Drop through
        !          3922:         and handle this like && and ||.  */
        !          3923: 
        !          3924:     case TRUTH_ANDIF_EXPR:
        !          3925:     case TRUTH_ORIF_EXPR:
        !          3926:       if (target == 0 || ! safe_from_p (target, exp)
        !          3927:          /* Make sure we don't have a hard reg (such as function's return
        !          3928:             value) live across basic blocks, if not optimizing.  */
        !          3929:          || (!optimize && GET_CODE (target) == REG
        !          3930:              && REGNO (target) < FIRST_PSEUDO_REGISTER))
        !          3931:        target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
        !          3932:       emit_clr_insn (target);
        !          3933:       op1 = gen_label_rtx ();
        !          3934:       jumpifnot (exp, op1);
        !          3935:       emit_0_to_1_insn (target);
        !          3936:       emit_label (op1);
        !          3937:       return target;
        !          3938: 
        !          3939:     case TRUTH_NOT_EXPR:
        !          3940:       op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0);
        !          3941:       /* The parser is careful to generate TRUTH_NOT_EXPR
        !          3942:         only with operands that are always zero or one.  */
        !          3943:       temp = expand_binop (mode, xor_optab, op0,
        !          3944:                           gen_rtx (CONST_INT, mode, 1),
        !          3945:                           target, 1, OPTAB_LIB_WIDEN);
        !          3946:       if (temp == 0)
        !          3947:        abort ();
        !          3948:       return temp;
        !          3949: 
        !          3950:     case COMPOUND_EXPR:
        !          3951:       expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0);
        !          3952:       emit_queue ();
        !          3953:       return expand_expr (TREE_OPERAND (exp, 1),
        !          3954:                          (ignore ? const0_rtx : target),
        !          3955:                          VOIDmode, 0);
        !          3956: 
        !          3957:     case COND_EXPR:
        !          3958:       {
        !          3959:        /* Note that COND_EXPRs whose type is a structure or union
        !          3960:           are required to be constructed to contain assignments of
        !          3961:           a temporary variable, so that we can evaluate them here
        !          3962:           for side effect only.  If type is void, we must do likewise.  */
        !          3963: 
        !          3964:        /* If an arm of the branch requires a cleanup,
        !          3965:           only that cleanup is performed.  */
        !          3966: 
        !          3967:        tree singleton = 0;
        !          3968:        tree binary_op = 0, unary_op = 0;
        !          3969:        tree old_cleanups = cleanups_this_call;
        !          3970:        cleanups_this_call = 0;
        !          3971: 
        !          3972:        /* If this is (A ? 1 : 0) and A is a condition, just evaluate it and
        !          3973:           convert it to our mode, if necessary.  */
        !          3974:        if (integer_onep (TREE_OPERAND (exp, 1))
        !          3975:            && integer_zerop (TREE_OPERAND (exp, 2))
        !          3976:            && TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == '<')
        !          3977:          {
        !          3978:            op0 = expand_expr (TREE_OPERAND (exp, 0), target, mode, modifier);
        !          3979:            if (GET_MODE (op0) == mode)
        !          3980:              return op0;
        !          3981:            if (target == 0)
        !          3982:              target = gen_reg_rtx (mode);
        !          3983:            convert_move (target, op0, unsignedp);
        !          3984:            return target;
        !          3985:          }
        !          3986: 
        !          3987:        /* If we are not to produce a result, we have no target.  Otherwise,
        !          3988:           if a target was specified use it; it will not be used as an
        !          3989:           intermediate target unless it is safe.  If no target, use a 
        !          3990:           temporary.  */
        !          3991: 
        !          3992:        if (mode == VOIDmode || ignore)
        !          3993:          temp = 0;
        !          3994:        else if (original_target
        !          3995:                 && safe_from_p (original_target, TREE_OPERAND (exp, 0)))
        !          3996:          temp = original_target;
        !          3997:        else if (mode == BLKmode)
        !          3998:          {
        !          3999:            if (TYPE_SIZE (type) == 0
        !          4000:                || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
        !          4001:              abort ();
        !          4002:            temp = assign_stack_temp (BLKmode,
        !          4003:                                      (TREE_INT_CST_LOW (TYPE_SIZE (type))
        !          4004:                                       + BITS_PER_UNIT - 1)
        !          4005:                                      / BITS_PER_UNIT, 0);
        !          4006:          }
        !          4007:        else
        !          4008:          temp = gen_reg_rtx (mode);
        !          4009: 
        !          4010:        /* Check for X ? A + B : A.  If we have this, we can copy
        !          4011:           A to the output and conditionally add B.  Similarly for unary
        !          4012:           operations.  Don't do this if X has side-effects because
        !          4013:           those side effects might affect A or B and the "?" operation is
        !          4014:           a sequence point in ANSI.  (We test for side effects later.)  */
        !          4015: 
        !          4016:        if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 1))) == '2'
        !          4017:            && operand_equal_p (TREE_OPERAND (exp, 2),
        !          4018:                                TREE_OPERAND (TREE_OPERAND (exp, 1), 0), 0))
        !          4019:          singleton = TREE_OPERAND (exp, 2), binary_op = TREE_OPERAND (exp, 1);
        !          4020:        else if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 2))) == '2'
        !          4021:                 && operand_equal_p (TREE_OPERAND (exp, 1),
        !          4022:                                     TREE_OPERAND (TREE_OPERAND (exp, 2), 0), 0))
        !          4023:          singleton = TREE_OPERAND (exp, 1), binary_op = TREE_OPERAND (exp, 2);
        !          4024:        else if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 1))) == '1'
        !          4025:                 && operand_equal_p (TREE_OPERAND (exp, 2),
        !          4026:                                     TREE_OPERAND (TREE_OPERAND (exp, 1), 0), 0))
        !          4027:          singleton = TREE_OPERAND (exp, 2), unary_op = TREE_OPERAND (exp, 1);
        !          4028:        else if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 2))) == '1'
        !          4029:                 && operand_equal_p (TREE_OPERAND (exp, 1),
        !          4030:                                     TREE_OPERAND (TREE_OPERAND (exp, 2), 0), 0))
        !          4031:          singleton = TREE_OPERAND (exp, 1), unary_op = TREE_OPERAND (exp, 2);
        !          4032: 
        !          4033:        /* If we had X ? A + 1 : A and we can do the test of X as a store-flag
        !          4034:           operation, do this as A + (X != 0).  Similarly for other simple
        !          4035:           binary operators.  */
        !          4036:        if (singleton && binary_op
        !          4037:            && ! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 0))
        !          4038:            && (TREE_CODE (binary_op) == PLUS_EXPR
        !          4039:                || TREE_CODE (binary_op) == MINUS_EXPR
        !          4040:                || TREE_CODE (binary_op) == BIT_IOR_EXPR
        !          4041:                || TREE_CODE (binary_op) == BIT_XOR_EXPR
        !          4042:                || TREE_CODE (binary_op) == BIT_AND_EXPR)
        !          4043:            && integer_onep (TREE_OPERAND (binary_op, 1))
        !          4044:            && TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == '<')
        !          4045:          {
        !          4046:            rtx result;
        !          4047:            optab boptab = (TREE_CODE (binary_op) == PLUS_EXPR ? add_optab
        !          4048:                            : TREE_CODE (binary_op) == MINUS_EXPR ? sub_optab
        !          4049:                            : TREE_CODE (binary_op) == BIT_IOR_EXPR ? ior_optab
        !          4050:                            : TREE_CODE (binary_op) == BIT_XOR_EXPR ? xor_optab
        !          4051:                            : and_optab);
        !          4052: 
        !          4053:            /* If we had X ? A : A + 1, do this as A + (X == 0).
        !          4054: 
        !          4055:               We have to invert the truth value here and then put it
        !          4056:               back later if do_store_flag fails.  We cannot simply copy
        !          4057:               TREE_OPERAND (exp, 0) to another variable and modify that
        !          4058:               because invert_truthvalue can modify the tree pointed to
        !          4059:               by its argument.  */
        !          4060:            if (singleton == TREE_OPERAND (exp, 1))
        !          4061:              TREE_OPERAND (exp, 0)
        !          4062:                = invert_truthvalue (TREE_OPERAND (exp, 0));
        !          4063: 
        !          4064:            result = do_store_flag (TREE_OPERAND (exp, 0),
        !          4065:                                    safe_from_p (temp, singleton) ? temp : 0,
        !          4066:                                    mode, BRANCH_COST <= 1);
        !          4067: 
        !          4068:            if (result)
        !          4069:              {
        !          4070:                op1 = expand_expr (singleton, 0, VOIDmode, 0);
        !          4071:                return expand_binop (mode, boptab, op1, result, temp,
        !          4072:                                     unsignedp, OPTAB_LIB_WIDEN);
        !          4073:              }
        !          4074:            else if (singleton == TREE_OPERAND (exp, 1))
        !          4075:              TREE_OPERAND (exp, 0)
        !          4076:                = invert_truthvalue (TREE_OPERAND (exp, 0));
        !          4077:          }
        !          4078:            
        !          4079:        NO_DEFER_POP;
        !          4080:        op0 = gen_label_rtx ();
        !          4081: 
        !          4082:        if (singleton && ! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 0)))
        !          4083:          {
        !          4084:            if (temp != 0)
        !          4085:              {
        !          4086:                /* If the target conflicts with the other operand of the
        !          4087:                   binary op, we can't use it.  Also, we can't use the target
        !          4088:                   if it is a hard register, because evaluating the condition
        !          4089:                   might clobber it.  */
        !          4090:                if ((binary_op
        !          4091:                     && ! safe_from_p (temp, TREE_OPERAND (binary_op, 1)))
        !          4092:                    || (GET_CODE (temp) == REG
        !          4093:                        && REGNO (temp) < FIRST_PSEUDO_REGISTER))
        !          4094:                  temp = gen_reg_rtx (mode);
        !          4095:                store_expr (singleton, temp, 0);
        !          4096:              }
        !          4097:            else
        !          4098:              expand_expr (singleton, ignore ? const1_rtx : 0, VOIDmode, 0);
        !          4099:            if (cleanups_this_call)
        !          4100:              {
        !          4101:                sorry ("aggregate value in COND_EXPR");
        !          4102:                cleanups_this_call = 0;
        !          4103:              }
        !          4104:            if (singleton == TREE_OPERAND (exp, 1))
        !          4105:              jumpif (TREE_OPERAND (exp, 0), op0);
        !          4106:            else
        !          4107:              jumpifnot (TREE_OPERAND (exp, 0), op0);
        !          4108: 
        !          4109:            if (binary_op && temp == 0)
        !          4110:              /* Just touch the other operand.  */
        !          4111:              expand_expr (TREE_OPERAND (binary_op, 1),
        !          4112:                           ignore ? const0_rtx : 0, VOIDmode, 0);
        !          4113:            else if (binary_op)
        !          4114:              store_expr (build (TREE_CODE (binary_op), type,
        !          4115:                                 make_tree (type, temp),
        !          4116:                                 TREE_OPERAND (binary_op, 1)),
        !          4117:                          temp, 0);
        !          4118:            else
        !          4119:              store_expr (build1 (TREE_CODE (unary_op), type,
        !          4120:                                  make_tree (type, temp)),
        !          4121:                          temp, 0);
        !          4122:            op1 = op0;
        !          4123:          }
        !          4124: #if 0
        !          4125:        /* This is now done in jump.c and is better done there because it
        !          4126:           produces shorter register lifetimes.  */
        !          4127:           
        !          4128:        /* Check for both possibilities either constants or variables
        !          4129:           in registers (but not the same as the target!).  If so, can
        !          4130:           save branches by assigning one, branching, and assigning the
        !          4131:           other.  */
        !          4132:        else if (temp && GET_MODE (temp) != BLKmode
        !          4133:                 && (TREE_CONSTANT (TREE_OPERAND (exp, 1))
        !          4134:                     || ((TREE_CODE (TREE_OPERAND (exp, 1)) == PARM_DECL
        !          4135:                          || TREE_CODE (TREE_OPERAND (exp, 1)) == VAR_DECL)
        !          4136:                         && DECL_RTL (TREE_OPERAND (exp, 1))
        !          4137:                         && GET_CODE (DECL_RTL (TREE_OPERAND (exp, 1))) == REG
        !          4138:                         && DECL_RTL (TREE_OPERAND (exp, 1)) != temp))
        !          4139:                 && (TREE_CONSTANT (TREE_OPERAND (exp, 2))
        !          4140:                     || ((TREE_CODE (TREE_OPERAND (exp, 2)) == PARM_DECL
        !          4141:                          || TREE_CODE (TREE_OPERAND (exp, 2)) == VAR_DECL)
        !          4142:                         && DECL_RTL (TREE_OPERAND (exp, 2))
        !          4143:                         && GET_CODE (DECL_RTL (TREE_OPERAND (exp, 2))) == REG
        !          4144:                         && DECL_RTL (TREE_OPERAND (exp, 2)) != temp)))
        !          4145:          {
        !          4146:            if (GET_CODE (temp) == REG && REGNO (temp) < FIRST_PSEUDO_REGISTER)
        !          4147:              temp = gen_reg_rtx (mode);
        !          4148:            store_expr (TREE_OPERAND (exp, 2), temp, 0);
        !          4149:            jumpifnot (TREE_OPERAND (exp, 0), op0);
        !          4150:            store_expr (TREE_OPERAND (exp, 1), temp, 0);
        !          4151:            op1 = op0;
        !          4152:          }
        !          4153: #endif
        !          4154:        /* Check for A op 0 ? A : FOO and A op 0 ? FOO : A where OP is any
        !          4155:           comparison operator.  If we have one of these cases, set the
        !          4156:           output to A, branch on A (cse will merge these two references),
        !          4157:           then set the output to FOO.  */
        !          4158:        else if (temp
        !          4159:                 && TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == '<'
        !          4160:                 && integer_zerop (TREE_OPERAND (TREE_OPERAND (exp, 0), 1))
        !          4161:                 && operand_equal_p (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
        !          4162:                                     TREE_OPERAND (exp, 1), 0)
        !          4163:                 && ! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 0))
        !          4164:                 && safe_from_p (temp, TREE_OPERAND (exp, 2)))
        !          4165:          {
        !          4166:            if (GET_CODE (temp) == REG && REGNO (temp) < FIRST_PSEUDO_REGISTER)
        !          4167:              temp = gen_reg_rtx (mode);
        !          4168:            store_expr (TREE_OPERAND (exp, 1), temp, 0);
        !          4169:            jumpif (TREE_OPERAND (exp, 0), op0);
        !          4170:            store_expr (TREE_OPERAND (exp, 2), temp, 0);
        !          4171:            op1 = op0;
        !          4172:          }
        !          4173:        else if (temp
        !          4174:                 && TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == '<'
        !          4175:                 && integer_zerop (TREE_OPERAND (TREE_OPERAND (exp, 0), 1))
        !          4176:                 && operand_equal_p (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
        !          4177:                                     TREE_OPERAND (exp, 2), 0)
        !          4178:                 && ! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 0))
        !          4179:                 && safe_from_p (temp, TREE_OPERAND (exp, 1)))
        !          4180:          {
        !          4181:            if (GET_CODE (temp) == REG && REGNO (temp) < FIRST_PSEUDO_REGISTER)
        !          4182:              temp = gen_reg_rtx (mode);
        !          4183:            store_expr (TREE_OPERAND (exp, 2), temp, 0);
        !          4184:            jumpifnot (TREE_OPERAND (exp, 0), op0);
        !          4185:            store_expr (TREE_OPERAND (exp, 1), temp, 0);
        !          4186:            op1 = op0;
        !          4187:          }
        !          4188:        else
        !          4189:          {
        !          4190:            op1 = gen_label_rtx ();
        !          4191:            jumpifnot (TREE_OPERAND (exp, 0), op0);
        !          4192:            if (temp != 0)
        !          4193:              store_expr (TREE_OPERAND (exp, 1), temp, 0);
        !          4194:            else
        !          4195:              expand_expr (TREE_OPERAND (exp, 1), ignore ? const0_rtx : 0,
        !          4196:                           VOIDmode, 0);
        !          4197:            if (cleanups_this_call)
        !          4198:              {
        !          4199:                sorry ("aggregate value in COND_EXPR");
        !          4200:                cleanups_this_call = 0;
        !          4201:              }
        !          4202: 
        !          4203:            emit_queue ();
        !          4204:            emit_jump_insn (gen_jump (op1));
        !          4205:            emit_barrier ();
        !          4206:            emit_label (op0);
        !          4207:            if (temp != 0)
        !          4208:              store_expr (TREE_OPERAND (exp, 2), temp, 0);
        !          4209:            else
        !          4210:              expand_expr (TREE_OPERAND (exp, 2), ignore ? const0_rtx : 0,
        !          4211:                           VOIDmode, 0);
        !          4212:          }
        !          4213: 
        !          4214:        if (cleanups_this_call)
        !          4215:          {
        !          4216:            sorry ("aggregate value in COND_EXPR");
        !          4217:            cleanups_this_call = 0;
        !          4218:          }
        !          4219: 
        !          4220:        emit_queue ();
        !          4221:        emit_label (op1);
        !          4222:        OK_DEFER_POP;
        !          4223:        cleanups_this_call = old_cleanups;
        !          4224:        return temp;
        !          4225:       }
        !          4226: 
        !          4227:     case TARGET_EXPR:
        !          4228:       {
        !          4229:        /* Something needs to be initialized, but we didn't know
        !          4230:           where that thing was when building the tree.  For example,
        !          4231:           it could be the return value of a function, or a parameter
        !          4232:           to a function which lays down in the stack, or a temporary
        !          4233:           variable which must be passed by reference.
        !          4234: 
        !          4235:           We guarantee that the expression will either be constructed
        !          4236:           or copied into our original target.  */
        !          4237: 
        !          4238:        tree slot = TREE_OPERAND (exp, 0);
        !          4239: 
        !          4240:        if (TREE_CODE (slot) != VAR_DECL)
        !          4241:          abort ();
        !          4242: 
        !          4243:        if (target == 0)
        !          4244:          {
        !          4245:            if (DECL_RTL (slot) != 0)
        !          4246:              target = DECL_RTL (slot);
        !          4247:            else
        !          4248:              {
        !          4249:                target = assign_stack_temp (mode, int_size_in_bytes (type), 0);
        !          4250:                /* All temp slots at this level must not conflict.  */
        !          4251:                preserve_temp_slots (target);
        !          4252:                DECL_RTL (slot) = target;
        !          4253:              }
        !          4254: 
        !          4255: #if 0
        !          4256:            /* Since SLOT is not known to the called function
        !          4257:               to belong to its stack frame, we must build an explicit
        !          4258:               cleanup.  This case occurs when we must build up a reference
        !          4259:               to pass the reference as an argument.  In this case,
        !          4260:               it is very likely that such a reference need not be
        !          4261:               built here.  */
        !          4262: 
        !          4263:            if (TREE_OPERAND (exp, 2) == 0)
        !          4264:              TREE_OPERAND (exp, 2) = maybe_build_cleanup (slot);
        !          4265:            if (TREE_OPERAND (exp, 2))
        !          4266:              cleanups_this_call = tree_cons (0, TREE_OPERAND (exp, 2),
        !          4267:                                                 cleanups_this_call);
        !          4268: #endif
        !          4269:          }
        !          4270:        else
        !          4271:          {
        !          4272:            /* This case does occur, when expanding a parameter which
        !          4273:               needs to be constructed on the stack.  The target
        !          4274:               is the actual stack address that we want to initialize.
        !          4275:               The function we call will perform the cleanup in this case.  */
        !          4276: 
        !          4277:            DECL_RTL (slot) = target;
        !          4278:          }
        !          4279: 
        !          4280:        return expand_expr (TREE_OPERAND (exp, 1), target, tmode, modifier);
        !          4281:       }
        !          4282: 
        !          4283:     case INIT_EXPR:
        !          4284:       {
        !          4285:        tree lhs = TREE_OPERAND (exp, 0);
        !          4286:        tree rhs = TREE_OPERAND (exp, 1);
        !          4287:        tree noncopied_parts = 0;
        !          4288:        tree lhs_type = TREE_TYPE (lhs);
        !          4289: 
        !          4290:        temp = expand_assignment (lhs, rhs, ! ignore, original_target != 0);
        !          4291:        if (TYPE_NONCOPIED_PARTS (lhs_type) != 0 && !fixed_type_p (rhs))
        !          4292:          noncopied_parts = init_noncopied_parts (stabilize_reference (lhs),
        !          4293:                                                  TYPE_NONCOPIED_PARTS (lhs_type));
        !          4294:        while (noncopied_parts != 0)
        !          4295:          {
        !          4296:            expand_assignment (TREE_VALUE (noncopied_parts),
        !          4297:                               TREE_PURPOSE (noncopied_parts), 0, 0);
        !          4298:            noncopied_parts = TREE_CHAIN (noncopied_parts);
        !          4299:          }
        !          4300:        return temp;
        !          4301:       }
        !          4302: 
        !          4303:     case MODIFY_EXPR:
        !          4304:       {
        !          4305:        /* If lhs is complex, expand calls in rhs before computing it.
        !          4306:           That's so we don't compute a pointer and save it over a call.
        !          4307:           If lhs is simple, compute it first so we can give it as a
        !          4308:           target if the rhs is just a call.  This avoids an extra temp and copy
        !          4309:           and that prevents a partial-subsumption which makes bad code.
        !          4310:           Actually we could treat component_ref's of vars like vars.  */
        !          4311: 
        !          4312:        tree lhs = TREE_OPERAND (exp, 0);
        !          4313:        tree rhs = TREE_OPERAND (exp, 1);
        !          4314:        tree noncopied_parts = 0;
        !          4315:        tree lhs_type = TREE_TYPE (lhs);
        !          4316: 
        !          4317:        temp = 0;
        !          4318: 
        !          4319:        if (TREE_CODE (lhs) != VAR_DECL
        !          4320:            && TREE_CODE (lhs) != RESULT_DECL
        !          4321:            && TREE_CODE (lhs) != PARM_DECL)
        !          4322:          preexpand_calls (exp);
        !          4323: 
        !          4324:        /* Check for |= or &= of a bitfield of size one into another bitfield
        !          4325:           of size 1.  In this case, (unless we need the result of the
        !          4326:           assignment) we can do this more efficiently with a
        !          4327:           test followed by an assignment, if necessary.
        !          4328: 
        !          4329:           ??? At this point, we can't get a BIT_FIELD_REF here.  But if
        !          4330:           things change so we do, this code should be enhanced to
        !          4331:           support it.  */
        !          4332:        if (ignore
        !          4333:            && TREE_CODE (lhs) == COMPONENT_REF
        !          4334:            && (TREE_CODE (rhs) == BIT_IOR_EXPR
        !          4335:                || TREE_CODE (rhs) == BIT_AND_EXPR)
        !          4336:            && TREE_OPERAND (rhs, 0) == lhs
        !          4337:            && TREE_CODE (TREE_OPERAND (rhs, 1)) == COMPONENT_REF
        !          4338:            && TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (lhs, 1))) == 1
        !          4339:            && TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (TREE_OPERAND (rhs, 1), 1))) == 1)
        !          4340:          {
        !          4341:            rtx label = gen_label_rtx ();
        !          4342: 
        !          4343:            do_jump (TREE_OPERAND (rhs, 1),
        !          4344:                     TREE_CODE (rhs) == BIT_IOR_EXPR ? label : 0,
        !          4345:                     TREE_CODE (rhs) == BIT_AND_EXPR ? label : 0);
        !          4346:            expand_assignment (lhs, convert (TREE_TYPE (rhs),
        !          4347:                                             (TREE_CODE (rhs) == BIT_IOR_EXPR
        !          4348:                                              ? integer_one_node
        !          4349:                                              : integer_zero_node)),
        !          4350:                               0, 0);
        !          4351:            emit_label (label);
        !          4352:            return const0_rtx;
        !          4353:          }
        !          4354: 
        !          4355:        if (TYPE_NONCOPIED_PARTS (lhs_type) != 0
        !          4356:            && ! (fixed_type_p (lhs) && fixed_type_p (rhs)))
        !          4357:          noncopied_parts = save_noncopied_parts (stabilize_reference (lhs),
        !          4358:                                                  TYPE_NONCOPIED_PARTS (lhs_type));
        !          4359: 
        !          4360:        temp = expand_assignment (lhs, rhs, ! ignore, original_target != 0);
        !          4361:        while (noncopied_parts != 0)
        !          4362:          {
        !          4363:            expand_assignment (TREE_PURPOSE (noncopied_parts),
        !          4364:                               TREE_VALUE (noncopied_parts), 0, 0);
        !          4365:            noncopied_parts = TREE_CHAIN (noncopied_parts);
        !          4366:          }
        !          4367:        return temp;
        !          4368:       }
        !          4369: 
        !          4370:     case PREINCREMENT_EXPR:
        !          4371:     case PREDECREMENT_EXPR:
        !          4372:       return expand_increment (exp, 0);
        !          4373: 
        !          4374:     case POSTINCREMENT_EXPR:
        !          4375:     case POSTDECREMENT_EXPR:
        !          4376:       /* Faster to treat as pre-increment if result is not used.  */
        !          4377:       return expand_increment (exp, ! ignore);
        !          4378: 
        !          4379:     case ADDR_EXPR:
        !          4380:       /* Are we taking the address of a nested function?  */
        !          4381:       if (TREE_CODE (TREE_OPERAND (exp, 0)) == FUNCTION_DECL
        !          4382:          && decl_function_context (TREE_OPERAND (exp, 0)) != 0)
        !          4383:        {
        !          4384:          op0 = trampoline_address (TREE_OPERAND (exp, 0));
        !          4385:          op0 = force_operand (op0, target);
        !          4386:        }
        !          4387:       else
        !          4388:        {
        !          4389:          op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode,
        !          4390:                             (modifier == EXPAND_INITIALIZER
        !          4391:                              ? modifier : EXPAND_CONST_ADDRESS));
        !          4392:          if (GET_CODE (op0) != MEM)
        !          4393:            abort ();
        !          4394:   
        !          4395:          if (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER)
        !          4396:            return XEXP (op0, 0);
        !          4397:          op0 = force_operand (XEXP (op0, 0), target);
        !          4398:        }
        !          4399:       if (flag_force_addr && GET_CODE (op0) != REG)
        !          4400:        return force_reg (Pmode, op0);
        !          4401:       return op0;
        !          4402: 
        !          4403:     case ENTRY_VALUE_EXPR:
        !          4404:       abort ();
        !          4405: 
        !          4406:     case ERROR_MARK:
        !          4407:       return const0_rtx;
        !          4408: 
        !          4409:     default:
        !          4410:       return (*lang_expand_expr) (exp, target, tmode, modifier);
        !          4411:     }
        !          4412: 
        !          4413:   /* Here to do an ordinary binary operator, generating an instruction
        !          4414:      from the optab already placed in `this_optab'.  */
        !          4415:  binop:
        !          4416:   preexpand_calls (exp);
        !          4417:   if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1)))
        !          4418:     subtarget = 0;
        !          4419:   op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
        !          4420:   op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
        !          4421:  binop2:
        !          4422:   temp = expand_binop (mode, this_optab, op0, op1, target,
        !          4423:                       unsignedp, OPTAB_LIB_WIDEN);
        !          4424:   if (temp == 0)
        !          4425:     abort ();
        !          4426:   return temp;
        !          4427: }
        !          4428: 
        !          4429: /* Return the alignment of EXP, a pointer valued expression for the mem*
        !          4430:    builtin functions.  Alignments greater than MAX_ALIGN are not significant.
        !          4431:    The alignment returned is, by default, the alignment of the thing that
        !          4432:    EXP points to (if it is not a POINTER_TYPE, 0 is returned).
        !          4433: 
        !          4434:    Otherwise, look at the expression to see if we can do better, i.e., if the
        !          4435:    expression is actually pointing at an object whose alignment is tighter.  */
        !          4436: 
        !          4437: static int
        !          4438: get_pointer_alignment (exp, max_align)
        !          4439:      tree exp;
        !          4440:      unsigned max_align;
        !          4441: {
        !          4442:   unsigned align, inner;
        !          4443: 
        !          4444:   if (TREE_CODE (TREE_TYPE (exp)) != POINTER_TYPE)
        !          4445:     return 0;
        !          4446: 
        !          4447:   align = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (exp)));
        !          4448:   align = MIN (align, max_align);
        !          4449: 
        !          4450:   while (1)
        !          4451:     {
        !          4452:       switch (TREE_CODE (exp))
        !          4453:        {
        !          4454:        case NOP_EXPR:
        !          4455:        case CONVERT_EXPR:
        !          4456:        case NON_LVALUE_EXPR:
        !          4457:          exp = TREE_OPERAND (exp, 0);
        !          4458:          if (TREE_CODE (TREE_TYPE (exp)) != POINTER_TYPE)
        !          4459:            return align;
        !          4460:          inner = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (exp)));
        !          4461:          inner = MIN (inner, max_align);
        !          4462:          align = MAX (align, inner);
        !          4463:          break;
        !          4464: 
        !          4465:        case PLUS_EXPR:
        !          4466:          /* If sum of pointer + int, restrict our maximum alignment to that
        !          4467:             imposed by the integer.  If not, we can't do any better than
        !          4468:             ALIGN.  */
        !          4469:          if (TREE_CODE (TREE_OPERAND (exp, 1)) != INTEGER_CST)
        !          4470:            return align;
        !          4471: 
        !          4472:          while ((TREE_INT_CST_LOW (TREE_OPERAND (exp, 1))
        !          4473:                  & (max_align - 1)) != 0)
        !          4474:            max_align >>= 1;
        !          4475: 
        !          4476:          exp = TREE_OPERAND (exp, 0);
        !          4477:          break;
        !          4478: 
        !          4479:        case ADDR_EXPR:
        !          4480:          /* See what we are pointing at and look at its alignment.  */
        !          4481:          exp = TREE_OPERAND (exp, 0);
        !          4482:          if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'd')
        !          4483:            align = MAX (align, DECL_ALIGN (exp));
        !          4484: #ifdef CONSTANT_ALIGNMENT
        !          4485:          else if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'c')
        !          4486:            align = CONSTANT_ALIGNMENT (exp, align);
        !          4487: #endif
        !          4488:          return MIN (align, max_align);
        !          4489: 
        !          4490:        default:
        !          4491:          return align;
        !          4492:        }
        !          4493:     }
        !          4494: }
        !          4495: 
        !          4496: /* Return the tree node and offset if a given argument corresponds to
        !          4497:    a string constant.  */
        !          4498: 
        !          4499: static tree
        !          4500: string_constant (arg, ptr_offset)
        !          4501:      tree arg;
        !          4502:      tree *ptr_offset;
        !          4503: {
        !          4504:   STRIP_NOPS (arg);
        !          4505: 
        !          4506:   if (TREE_CODE (arg) == ADDR_EXPR
        !          4507:       && TREE_CODE (TREE_OPERAND (arg, 0)) == STRING_CST)
        !          4508:     {
        !          4509:       *ptr_offset = integer_zero_node;
        !          4510:       return TREE_OPERAND (arg, 0);
        !          4511:     }
        !          4512:   else if (TREE_CODE (arg) == PLUS_EXPR)
        !          4513:     {
        !          4514:       tree arg0 = TREE_OPERAND (arg, 0);
        !          4515:       tree arg1 = TREE_OPERAND (arg, 1);
        !          4516: 
        !          4517:       STRIP_NOPS (arg0);
        !          4518:       STRIP_NOPS (arg1);
        !          4519: 
        !          4520:       if (TREE_CODE (arg0) == ADDR_EXPR
        !          4521:          && TREE_CODE (TREE_OPERAND (arg0, 0)) == STRING_CST)
        !          4522:        {
        !          4523:          *ptr_offset = arg1;
        !          4524:          return TREE_OPERAND (arg0, 0);
        !          4525:        }
        !          4526:       else if (TREE_CODE (arg1) == ADDR_EXPR
        !          4527:               && TREE_CODE (TREE_OPERAND (arg1, 0)) == STRING_CST)
        !          4528:        {
        !          4529:          *ptr_offset = arg0;
        !          4530:          return TREE_OPERAND (arg1, 0);
        !          4531:        }
        !          4532:     }
        !          4533: 
        !          4534:   return 0;
        !          4535: }
        !          4536: 
        !          4537: /* Compute the length of a C string.  TREE_STRING_LENGTH is not the right
        !          4538:    way, because it could contain a zero byte in the middle.
        !          4539:    TREE_STRING_LENGTH is the size of the character array, not the string.
        !          4540: 
        !          4541:    Unfortunately, string_constant can't access the values of const char
        !          4542:    arrays with initializers, so neither can we do so here.  */
        !          4543: 
        !          4544: static tree
        !          4545: c_strlen (src)
        !          4546:      tree src;
        !          4547: {
        !          4548:   tree offset_node;
        !          4549:   int offset, max;
        !          4550:   char *ptr;
        !          4551: 
        !          4552:   src = string_constant (src, &offset_node);
        !          4553:   if (src == 0)
        !          4554:     return 0;
        !          4555:   max = TREE_STRING_LENGTH (src);
        !          4556:   ptr = TREE_STRING_POINTER (src);
        !          4557:   if (offset_node && TREE_CODE (offset_node) != INTEGER_CST)
        !          4558:     {
        !          4559:       /* If the string has an internal zero byte (e.g., "foo\0bar"), we can't
        !          4560:         compute the offset to the following null if we don't know where to
        !          4561:         start searching for it.  */
        !          4562:       int i;
        !          4563:       for (i = 0; i < max; i++)
        !          4564:        if (ptr[i] == 0)
        !          4565:          return 0;
        !          4566:       /* We don't know the starting offset, but we do know that the string
        !          4567:         has no internal zero bytes.  We can assume that the offset falls
        !          4568:         within the bounds of the string; otherwise, the programmer deserves
        !          4569:         what he gets.  Subtract the offset from the length of the string,
        !          4570:         and return that.  */
        !          4571:       /* This would perhaps not be valid if we were dealing with named
        !          4572:          arrays in addition to literal string constants.  */
        !          4573:       return size_binop (MINUS_EXPR, size_int (max), offset_node);
        !          4574:     }
        !          4575: 
        !          4576:   /* We have a known offset into the string.  Start searching there for
        !          4577:      a null character.  */
        !          4578:   if (offset_node == 0)
        !          4579:     offset = 0;
        !          4580:   else
        !          4581:     {
        !          4582:       /* Did we get a long long offset?  If so, punt.  */
        !          4583:       if (TREE_INT_CST_HIGH (offset_node) != 0)
        !          4584:        return 0;
        !          4585:       offset = TREE_INT_CST_LOW (offset_node);
        !          4586:     }
        !          4587:   /* If the offset is known to be out of bounds, warn, and call strlen at
        !          4588:      runtime.  */
        !          4589:   if (offset < 0 || offset > max)
        !          4590:     {
        !          4591:       warning ("offset outside bounds of constant string");
        !          4592:       return 0;
        !          4593:     }
        !          4594:   /* Use strlen to search for the first zero byte.  Since any strings
        !          4595:      constructed with build_string will have nulls appended, we win even
        !          4596:      if we get handed something like (char[4])"abcd".
        !          4597: 
        !          4598:      Since OFFSET is our starting index into the string, no further
        !          4599:      calculation is needed.  */
        !          4600:   return size_int (strlen (ptr + offset));
        !          4601: }
        !          4602: 
        !          4603: /* Expand an expression EXP that calls a built-in function,
        !          4604:    with result going to TARGET if that's convenient
        !          4605:    (and in mode MODE if that's convenient).
        !          4606:    SUBTARGET may be used as the target for computing one of EXP's operands.
        !          4607:    IGNORE is nonzero if the value is to be ignored.  */
        !          4608: 
        !          4609: static rtx
        !          4610: expand_builtin (exp, target, subtarget, mode, ignore)
        !          4611:      tree exp;
        !          4612:      rtx target;
        !          4613:      rtx subtarget;
        !          4614:      enum machine_mode mode;
        !          4615:      int ignore;
        !          4616: {
        !          4617:   tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
        !          4618:   tree arglist = TREE_OPERAND (exp, 1);
        !          4619:   rtx op0;
        !          4620:   enum machine_mode value_mode = TYPE_MODE (TREE_TYPE (exp));
        !          4621: 
        !          4622:   switch (DECL_FUNCTION_CODE (fndecl))
        !          4623:     {
        !          4624:     case BUILT_IN_ABS:
        !          4625:     case BUILT_IN_LABS:
        !          4626:     case BUILT_IN_FABS:
        !          4627:       /* build_function_call changes these into ABS_EXPR.  */
        !          4628:       abort ();
        !          4629: 
        !          4630:     case BUILT_IN_SAVEREGS:
        !          4631:       /* Don't do __builtin_saveregs more than once in a function.
        !          4632:         Save the result of the first call and reuse it.  */
        !          4633:       if (saveregs_value != 0)
        !          4634:        return saveregs_value;
        !          4635:       {
        !          4636:        /* When this function is called, it means that registers must be
        !          4637:           saved on entry to this function.  So we migrate the
        !          4638:           call to the first insn of this function.  */
        !          4639:        rtx temp;
        !          4640:        rtx seq;
        !          4641:        rtx valreg, saved_valreg;
        !          4642: 
        !          4643:        /* Now really call the function.  `expand_call' does not call
        !          4644:           expand_builtin, so there is no danger of infinite recursion here.  */
        !          4645:        start_sequence ();
        !          4646: 
        !          4647: #ifdef EXPAND_BUILTIN_SAVEREGS
        !          4648:        /* Do whatever the machine needs done in this case.  */
        !          4649:        temp = EXPAND_BUILTIN_SAVEREGS (arglist);
        !          4650: #else
        !          4651:        /* The register where the function returns its value
        !          4652:           is likely to have something else in it, such as an argument.
        !          4653:           So preserve that register around the call.  */
        !          4654:        if (value_mode != VOIDmode)
        !          4655:          {
        !          4656:            valreg = hard_libcall_value (value_mode);
        !          4657:            saved_valreg = gen_reg_rtx (value_mode);
        !          4658:            emit_move_insn (saved_valreg, valreg);
        !          4659:          }
        !          4660: 
        !          4661:        /* Generate the call, putting the value in a pseudo.  */
        !          4662:        temp = expand_call (exp, target, ignore);
        !          4663: 
        !          4664:        if (value_mode != VOIDmode)
        !          4665:          emit_move_insn (valreg, saved_valreg);
        !          4666: #endif
        !          4667: 
        !          4668:        seq = get_insns ();
        !          4669:        end_sequence ();
        !          4670: 
        !          4671:        saveregs_value = temp;
        !          4672: 
        !          4673:        /* This won't work inside a SEQUENCE--it really has to be
        !          4674:           at the start of the function.  */
        !          4675:        if (in_sequence_p ())
        !          4676:          {
        !          4677:            /* Better to do this than to crash.  */
        !          4678:            error ("`va_start' used within `({...})'");
        !          4679:            return temp;
        !          4680:          }
        !          4681: 
        !          4682:        /* Put the sequence after the NOTE that starts the function.  */
        !          4683:        emit_insns_before (seq, NEXT_INSN (get_insns ()));
        !          4684:        return temp;
        !          4685:       }
        !          4686: 
        !          4687:       /* __builtin_args_info (N) returns word N of the arg space info
        !          4688:         for the current function.  The number and meanings of words
        !          4689:         is controlled by the definition of CUMULATIVE_ARGS.  */
        !          4690:     case BUILT_IN_ARGS_INFO:
        !          4691:       {
        !          4692:        int nwords = sizeof (CUMULATIVE_ARGS) / sizeof (int);
        !          4693:        int i;
        !          4694:        int *word_ptr = (int *) &current_function_args_info;
        !          4695:        tree type, elts, result;
        !          4696: 
        !          4697:        if (sizeof (CUMULATIVE_ARGS) % sizeof (int) != 0)
        !          4698:          fatal ("CUMULATIVE_ARGS type defined badly; see %s, line %d",
        !          4699:                 __FILE__, __LINE__);
        !          4700: 
        !          4701:        if (arglist != 0)
        !          4702:          {
        !          4703:            tree arg = TREE_VALUE (arglist);
        !          4704:            if (TREE_CODE (arg) != INTEGER_CST)
        !          4705:              error ("argument of __builtin_args_info must be constant");
        !          4706:            else
        !          4707:              {
        !          4708:                int wordnum = TREE_INT_CST_LOW (arg);
        !          4709: 
        !          4710:                if (wordnum < 0 || wordnum >= nwords)
        !          4711:                  error ("argument of __builtin_args_info out of range");
        !          4712:                else
        !          4713:                  return gen_rtx (CONST_INT, VOIDmode, word_ptr[wordnum]);
        !          4714:              }
        !          4715:          }
        !          4716:        else
        !          4717:          error ("missing argument in __builtin_args_info");
        !          4718: 
        !          4719:        return const0_rtx;
        !          4720: 
        !          4721: #if 0
        !          4722:        for (i = 0; i < nwords; i++)
        !          4723:          elts = tree_cons (NULL_TREE, build_int_2 (word_ptr[i], 0));
        !          4724: 
        !          4725:        type = build_array_type (integer_type_node,
        !          4726:                                 build_index_type (build_int_2 (nwords, 0)));
        !          4727:        result = build (CONSTRUCTOR, type, NULL_TREE, nreverse (elts));
        !          4728:        TREE_CONSTANT (result) = 1;
        !          4729:        TREE_STATIC (result) = 1;
        !          4730:        result = build (INDIRECT_REF, build_pointer_type (type), result);
        !          4731:        TREE_CONSTANT (result) = 1;
        !          4732:        return expand_expr (result, 0, VOIDmode, 0);
        !          4733: #endif
        !          4734:       }
        !          4735: 
        !          4736:       /* Return the address of the first anonymous stack arg.  */
        !          4737:     case BUILT_IN_NEXT_ARG:
        !          4738:       {
        !          4739:        tree fntype = TREE_TYPE (current_function_decl);
        !          4740:        if (!(TYPE_ARG_TYPES (fntype) != 0
        !          4741:              && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
        !          4742:                  != void_type_node)))
        !          4743:          {
        !          4744:            error ("`va_start' used in function with fixed args");
        !          4745:            return const0_rtx;
        !          4746:          }
        !          4747:       }
        !          4748: 
        !          4749:       return expand_binop (Pmode, add_optab,
        !          4750:                           current_function_internal_arg_pointer,
        !          4751:                           current_function_arg_offset_rtx,
        !          4752:                           0, 0, OPTAB_LIB_WIDEN);
        !          4753: 
        !          4754:     case BUILT_IN_CLASSIFY_TYPE:
        !          4755:       if (arglist != 0)
        !          4756:        {
        !          4757:          tree type = TREE_TYPE (TREE_VALUE (arglist));
        !          4758:          enum tree_code code = TREE_CODE (type);
        !          4759:          if (code == VOID_TYPE)
        !          4760:            return gen_rtx (CONST_INT, VOIDmode, void_type_class);
        !          4761:          if (code == INTEGER_TYPE)
        !          4762:            return gen_rtx (CONST_INT, VOIDmode, integer_type_class);
        !          4763:          if (code == CHAR_TYPE)
        !          4764:            return gen_rtx (CONST_INT, VOIDmode, char_type_class);
        !          4765:          if (code == ENUMERAL_TYPE)
        !          4766:            return gen_rtx (CONST_INT, VOIDmode, enumeral_type_class);
        !          4767:          if (code == BOOLEAN_TYPE)
        !          4768:            return gen_rtx (CONST_INT, VOIDmode, boolean_type_class);
        !          4769:          if (code == POINTER_TYPE)
        !          4770:            return gen_rtx (CONST_INT, VOIDmode, pointer_type_class);
        !          4771:          if (code == REFERENCE_TYPE)
        !          4772:            return gen_rtx (CONST_INT, VOIDmode, reference_type_class);
        !          4773:          if (code == OFFSET_TYPE)
        !          4774:            return gen_rtx (CONST_INT, VOIDmode, offset_type_class);
        !          4775:          if (code == REAL_TYPE)
        !          4776:            return gen_rtx (CONST_INT, VOIDmode, real_type_class);
        !          4777:          if (code == COMPLEX_TYPE)
        !          4778:            return gen_rtx (CONST_INT, VOIDmode, complex_type_class);
        !          4779:          if (code == FUNCTION_TYPE)
        !          4780:            return gen_rtx (CONST_INT, VOIDmode, function_type_class);
        !          4781:          if (code == METHOD_TYPE)
        !          4782:            return gen_rtx (CONST_INT, VOIDmode, method_type_class);
        !          4783:          if (code == RECORD_TYPE)
        !          4784:            return gen_rtx (CONST_INT, VOIDmode, record_type_class);
        !          4785:          if (code == UNION_TYPE)
        !          4786:            return gen_rtx (CONST_INT, VOIDmode, union_type_class);
        !          4787:          if (code == ARRAY_TYPE)
        !          4788:            return gen_rtx (CONST_INT, VOIDmode, array_type_class);
        !          4789:          if (code == STRING_TYPE)
        !          4790:            return gen_rtx (CONST_INT, VOIDmode, string_type_class);
        !          4791:          if (code == SET_TYPE)
        !          4792:            return gen_rtx (CONST_INT, VOIDmode, set_type_class);
        !          4793:          if (code == FILE_TYPE)
        !          4794:            return gen_rtx (CONST_INT, VOIDmode, file_type_class);
        !          4795:          if (code == LANG_TYPE)
        !          4796:            return gen_rtx (CONST_INT, VOIDmode, lang_type_class);
        !          4797:        }
        !          4798:       return gen_rtx (CONST_INT, VOIDmode, no_type_class);
        !          4799: 
        !          4800:     case BUILT_IN_CONSTANT_P:
        !          4801:       if (arglist == 0)
        !          4802:        return const0_rtx;
        !          4803:       else
        !          4804:        return (TREE_CODE_CLASS (TREE_VALUE (arglist)) == 'c'
        !          4805:                ? const1_rtx : const0_rtx);
        !          4806: 
        !          4807:     case BUILT_IN_FRAME_ADDRESS:
        !          4808:       /* The argument must be a nonnegative integer constant.
        !          4809:         It counts the number of frames to scan up the stack.
        !          4810:         The value is the address of that frame.  */
        !          4811:     case BUILT_IN_RETURN_ADDRESS:
        !          4812:       /* The argument must be a nonnegative integer constant.
        !          4813:         It counts the number of frames to scan up the stack.
        !          4814:         The value is the return address saved in that frame.  */
        !          4815:       if (arglist == 0)
        !          4816:        /* Warning about missing arg was already issued.  */
        !          4817:        return const0_rtx;
        !          4818:       else if (TREE_CODE (TREE_VALUE (arglist)) != INTEGER_CST)
        !          4819:        {
        !          4820:          error ("invalid arg to __builtin_return_address");
        !          4821:          return const0_rtx;
        !          4822:        }
        !          4823:       else if (tree_int_cst_lt (TREE_VALUE (arglist), integer_zero_node))
        !          4824:        {
        !          4825:          error ("invalid arg to __builtin_return_address");
        !          4826:          return const0_rtx;
        !          4827:        }
        !          4828:       else
        !          4829:        {
        !          4830:          int count = TREE_INT_CST_LOW (TREE_VALUE (arglist)); 
        !          4831:          rtx tem = frame_pointer_rtx;
        !          4832:          int i;
        !          4833: 
        !          4834:          /* Scan back COUNT frames to the specified frame.  */
        !          4835:          for (i = 0; i < count; i++)
        !          4836:            {
        !          4837:              /* Assume the dynamic chain pointer is in the word that
        !          4838:                 the frame address points to, unless otherwise specified.  */
        !          4839: #ifdef DYNAMIC_CHAIN_ADDRESS
        !          4840:              tem = DYNAMIC_CHAIN_ADDRESS (tem);
        !          4841: #endif
        !          4842:              tem = memory_address (Pmode, tem);
        !          4843:              tem = copy_to_reg (gen_rtx (MEM, Pmode, tem));
        !          4844:            }
        !          4845: 
        !          4846:          /* For __builtin_frame_address, return what we've got.  */
        !          4847:          if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
        !          4848:            return tem;
        !          4849: 
        !          4850:          /* For __builtin_return_address,
        !          4851:             Get the return address from that frame.  */
        !          4852: #ifdef RETURN_ADDR_RTX
        !          4853:          return RETURN_ADDR_RTX (count, tem);
        !          4854: #else
        !          4855:          tem = memory_address (Pmode,
        !          4856:                                plus_constant (tem, GET_MODE_SIZE (Pmode)));
        !          4857:          return copy_to_reg (gen_rtx (MEM, Pmode, tem));
        !          4858: #endif
        !          4859:        }
        !          4860: 
        !          4861:     case BUILT_IN_ALLOCA:
        !          4862:       if (arglist == 0
        !          4863:          /* Arg could be non-integer if user redeclared this fcn wrong.  */
        !          4864:          || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE)
        !          4865:        return const0_rtx;
        !          4866:       current_function_calls_alloca = 1;
        !          4867:       /* Compute the argument.  */
        !          4868:       op0 = expand_expr (TREE_VALUE (arglist), 0, VOIDmode, 0);
        !          4869: 
        !          4870:       /* Allocate the desired space.  */
        !          4871:       target = allocate_dynamic_stack_space (op0, target);
        !          4872: 
        !          4873:       /* Record the new stack level for nonlocal gotos.  */
        !          4874:       if (nonlocal_goto_stack_level != 0)
        !          4875:        emit_move_insn (nonlocal_goto_stack_level, stack_pointer_rtx);
        !          4876:       return target;
        !          4877: 
        !          4878:     case BUILT_IN_FFS:
        !          4879:       /* If not optimizing, call the library function.  */
        !          4880:       if (!optimize)
        !          4881:        break;
        !          4882: 
        !          4883:       if (arglist == 0
        !          4884:          /* Arg could be non-integer if user redeclared this fcn wrong.  */
        !          4885:          || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE)
        !          4886:        return const0_rtx;
        !          4887: 
        !          4888:       /* Compute the argument.  */
        !          4889:       op0 = expand_expr (TREE_VALUE (arglist), subtarget, VOIDmode, 0);
        !          4890:       /* Compute ffs, into TARGET if possible.
        !          4891:         Set TARGET to wherever the result comes back.  */
        !          4892:       target = expand_unop (TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist))),
        !          4893:                            ffs_optab, op0, target, 1);
        !          4894:       if (target == 0)
        !          4895:        abort ();
        !          4896:       return target;
        !          4897: 
        !          4898:     case BUILT_IN_STRLEN:
        !          4899:       /* If not optimizing, call the library function.  */
        !          4900:       if (!optimize)
        !          4901:        break;
        !          4902: 
        !          4903:       if (arglist == 0
        !          4904:          /* Arg could be non-pointer if user redeclared this fcn wrong.  */
        !          4905:          || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE)
        !          4906:        return const0_rtx;
        !          4907:       else
        !          4908:        {
        !          4909:          tree len = c_strlen (TREE_VALUE (arglist));
        !          4910: 
        !          4911:          if (len == 0)
        !          4912:            break;
        !          4913:          return expand_expr (len, target, mode, 0);
        !          4914:        }
        !          4915: 
        !          4916:     case BUILT_IN_STRCPY:
        !          4917:       /* If not optimizing, call the library function.  */
        !          4918:       if (!optimize)
        !          4919:        break;
        !          4920: 
        !          4921:       if (arglist == 0
        !          4922:          /* Arg could be non-pointer if user redeclared this fcn wrong.  */
        !          4923:          || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
        !          4924:          || TREE_CHAIN (arglist) == 0
        !          4925:          || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != POINTER_TYPE)
        !          4926:        return const0_rtx;
        !          4927:       else
        !          4928:        {
        !          4929:          tree len = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)));
        !          4930: 
        !          4931:          if (len == 0)
        !          4932:            break;
        !          4933: 
        !          4934:          len = size_binop (PLUS_EXPR, len, integer_one_node);
        !          4935: 
        !          4936:          chainon (arglist, build_tree_list (0, len));
        !          4937:        }
        !          4938: 
        !          4939:       /* Drops in.  */
        !          4940:     case BUILT_IN_MEMCPY:
        !          4941:       /* If not optimizing, call the library function.  */
        !          4942:       if (!optimize)
        !          4943:        break;
        !          4944: 
        !          4945:       if (arglist == 0
        !          4946:          /* Arg could be non-pointer if user redeclared this fcn wrong.  */
        !          4947:          || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
        !          4948:          || TREE_CHAIN (arglist) == 0
        !          4949:          || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != POINTER_TYPE
        !          4950:          || TREE_CHAIN (TREE_CHAIN (arglist)) == 0
        !          4951:          || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))))) != INTEGER_TYPE)
        !          4952:        return const0_rtx;
        !          4953:       else
        !          4954:        {
        !          4955:          tree dest = TREE_VALUE (arglist);
        !          4956:          tree src = TREE_VALUE (TREE_CHAIN (arglist));
        !          4957:          tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
        !          4958: 
        !          4959:          int src_align
        !          4960:            = get_pointer_alignment (src, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
        !          4961:          int dest_align
        !          4962:            = get_pointer_alignment (dest, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
        !          4963:          rtx dest_rtx;
        !          4964: 
        !          4965:          /* If either SRC or DEST is not a pointer type, don't do
        !          4966:             this operation in-line.  */
        !          4967:          if (src_align == 0 || dest_align == 0)
        !          4968:            {
        !          4969:              if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STRCPY)
        !          4970:                TREE_CHAIN (TREE_CHAIN (arglist)) = 0;
        !          4971:              break;
        !          4972:            }
        !          4973: 
        !          4974:          dest_rtx = expand_expr (dest, 0, Pmode, EXPAND_NORMAL);
        !          4975: 
        !          4976:          /* Copy word part most expediently.  */
        !          4977:          emit_block_move (gen_rtx (MEM, BLKmode,
        !          4978:                                    memory_address (BLKmode, dest_rtx)),
        !          4979:                           gen_rtx (MEM, BLKmode,
        !          4980:                                    memory_address (BLKmode,
        !          4981:                                                    expand_expr (src, 0, Pmode,
        !          4982:                                                                 EXPAND_NORMAL))),
        !          4983:                           expand_expr (len, 0, VOIDmode, 0),
        !          4984:                           MIN (src_align, dest_align));
        !          4985:          return dest_rtx;
        !          4986:        }
        !          4987: 
        !          4988: /* These comparison functions need an instruction that returns an actual
        !          4989:    index.  An ordinary compare that just sets the condition codes
        !          4990:    is not enough.  */
        !          4991: #ifdef HAVE_cmpstrsi
        !          4992:     case BUILT_IN_STRCMP:
        !          4993:       /* If not optimizing, call the library function.  */
        !          4994:       if (!optimize)
        !          4995:        break;
        !          4996: 
        !          4997:       if (arglist == 0
        !          4998:          /* Arg could be non-pointer if user redeclared this fcn wrong.  */
        !          4999:          || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
        !          5000:          || TREE_CHAIN (arglist) == 0
        !          5001:          || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != POINTER_TYPE)
        !          5002:        return const0_rtx;
        !          5003:       else if (!HAVE_cmpstrsi)
        !          5004:        break;
        !          5005:       {
        !          5006:        tree arg1 = TREE_VALUE (arglist);
        !          5007:        tree arg2 = TREE_VALUE (TREE_CHAIN (arglist));
        !          5008:        tree offset;
        !          5009:        tree len, len2;
        !          5010: 
        !          5011:        len = c_strlen (arg1);
        !          5012:        if (len)
        !          5013:          len = size_binop (PLUS_EXPR, integer_one_node, len);
        !          5014:        len2 = c_strlen (arg2);
        !          5015:        if (len2)
        !          5016:          len2 = size_binop (PLUS_EXPR, integer_one_node, len2);
        !          5017: 
        !          5018:        /* If we don't have a constant length for the first, use the length
        !          5019:           of the second, if we know it.  We don't require a constant for
        !          5020:           this case; some cost analysis could be done if both are available
        !          5021:           but neither is constant.  For now, assume they're equally cheap.
        !          5022: 
        !          5023:           If both strings have constant lengths, use the smaller.  This
        !          5024:           could arise if optimization results in strcpy being called with
        !          5025:           two fixed strings, or if the code was machine-generated.  We should
        !          5026:           add some code to the `memcmp' handler below to deal with such
        !          5027:           situations, someday.  */
        !          5028:        if (!len || TREE_CODE (len) != INTEGER_CST)
        !          5029:          {
        !          5030:            if (len2)
        !          5031:              len = len2;
        !          5032:            else if (len == 0)
        !          5033:              break;
        !          5034:          }
        !          5035:        else if (len2 && TREE_CODE (len2) == INTEGER_CST)
        !          5036:          {
        !          5037:            if (tree_int_cst_lt (len2, len))
        !          5038:              len = len2;
        !          5039:          }
        !          5040: 
        !          5041:        chainon (arglist, build_tree_list (0, len));
        !          5042:       }
        !          5043: 
        !          5044:       /* Drops in.  */
        !          5045:     case BUILT_IN_MEMCMP:
        !          5046:       /* If not optimizing, call the library function.  */
        !          5047:       if (!optimize)
        !          5048:        break;
        !          5049: 
        !          5050:       if (arglist == 0
        !          5051:          /* Arg could be non-pointer if user redeclared this fcn wrong.  */
        !          5052:          || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
        !          5053:          || TREE_CHAIN (arglist) == 0
        !          5054:          || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != POINTER_TYPE
        !          5055:          || TREE_CHAIN (TREE_CHAIN (arglist)) == 0
        !          5056:          || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))))) != INTEGER_TYPE)
        !          5057:        return const0_rtx;
        !          5058:       else if (!HAVE_cmpstrsi)
        !          5059:        break;
        !          5060:       {
        !          5061:        tree arg1 = TREE_VALUE (arglist);
        !          5062:        tree arg2 = TREE_VALUE (TREE_CHAIN (arglist));
        !          5063:        tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
        !          5064:        rtx result;
        !          5065: 
        !          5066:        int arg1_align
        !          5067:          = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
        !          5068:        int arg2_align
        !          5069:          = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
        !          5070:        enum machine_mode insn_mode
        !          5071:          = insn_operand_mode[(int) CODE_FOR_cmpstrsi][0];
        !          5072: 
        !          5073:        /* If we don't have POINTER_TYPE, call the function.  */
        !          5074:        if (arg1_align == 0 || arg2_align == 0)
        !          5075:          {
        !          5076:            if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STRCMP)
        !          5077:              TREE_CHAIN (TREE_CHAIN (arglist)) = 0;
        !          5078:            break;
        !          5079:          }
        !          5080: 
        !          5081:        /* Make a place to write the result of the instruction.  */
        !          5082:        result = target;
        !          5083:        if (! (result != 0
        !          5084:               && GET_CODE (result) == REG && GET_MODE (result) == insn_mode
        !          5085:               && REGNO (result) >= FIRST_PSEUDO_REGISTER))
        !          5086:          result = gen_reg_rtx (insn_mode);
        !          5087: 
        !          5088:        emit_insn (gen_cmpstrsi (result,
        !          5089:                                 gen_rtx (MEM, BLKmode,
        !          5090:                                          expand_expr (arg1, 0, Pmode, EXPAND_NORMAL)),
        !          5091:                                 gen_rtx (MEM, BLKmode,
        !          5092:                                          expand_expr (arg2, 0, Pmode, EXPAND_NORMAL)),
        !          5093:                                 expand_expr (len, 0, VOIDmode, 0),
        !          5094:                                 gen_rtx (CONST_INT, VOIDmode,
        !          5095:                                          MIN (arg1_align, arg2_align))));
        !          5096: 
        !          5097:        /* Return the value in the proper mode for this function.  */
        !          5098:        mode = TYPE_MODE (TREE_TYPE (exp));
        !          5099:        if (GET_MODE (result) == mode)
        !          5100:          return result;
        !          5101:        else if (target != 0)
        !          5102:          {
        !          5103:            convert_move (target, result, 0);
        !          5104:            return target;
        !          5105:          }
        !          5106:        else
        !          5107:          return convert_to_mode (mode, result, 0);
        !          5108:       }        
        !          5109: #else
        !          5110:     case BUILT_IN_STRCMP:
        !          5111:     case BUILT_IN_MEMCMP:
        !          5112:       break;
        !          5113: #endif
        !          5114: 
        !          5115:     default:                   /* just do library call, if unknown builtin */
        !          5116:       error ("built-in function %s not currently supported",
        !          5117:             IDENTIFIER_POINTER (DECL_NAME (fndecl)));
        !          5118:     }
        !          5119: 
        !          5120:   /* The switch statement above can drop through to cause the function
        !          5121:      to be called normally.  */
        !          5122: 
        !          5123:   return expand_call (exp, target, ignore);
        !          5124: }
        !          5125: 
        !          5126: /* Expand code for a post- or pre- increment or decrement
        !          5127:    and return the RTX for the result.
        !          5128:    POST is 1 for postinc/decrements and 0 for preinc/decrements.  */
        !          5129: 
        !          5130: static rtx
        !          5131: expand_increment (exp, post)
        !          5132:      register tree exp;
        !          5133:      int post;
        !          5134: {
        !          5135:   register rtx op0, op1;
        !          5136:   register rtx temp, value;
        !          5137:   register tree incremented = TREE_OPERAND (exp, 0);
        !          5138:   optab this_optab = add_optab;
        !          5139:   int icode;
        !          5140:   enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
        !          5141:   int op0_is_copy = 0;
        !          5142: 
        !          5143:   /* Stabilize any component ref that might need to be
        !          5144:      evaluated more than once below.  */
        !          5145:   if (TREE_CODE (incremented) == BIT_FIELD_REF
        !          5146:       || (TREE_CODE (incremented) == COMPONENT_REF
        !          5147:          && (TREE_CODE (TREE_OPERAND (incremented, 0)) != INDIRECT_REF
        !          5148:              || DECL_BIT_FIELD (TREE_OPERAND (incremented, 1)))))
        !          5149:     incremented = stabilize_reference (incremented);
        !          5150: 
        !          5151:   /* Compute the operands as RTX.
        !          5152:      Note whether OP0 is the actual lvalue or a copy of it:
        !          5153:      I believe it is a copy iff it is a register and insns were
        !          5154:      generated in computing it.  */
        !          5155:   temp = get_last_insn ();
        !          5156:   op0 = expand_expr (incremented, 0, VOIDmode, 0);
        !          5157:   if (temp != get_last_insn ())
        !          5158:     op0_is_copy = (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG);
        !          5159:   op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
        !          5160: 
        !          5161:   /* Decide whether incrementing or decrementing.  */
        !          5162:   if (TREE_CODE (exp) == POSTDECREMENT_EXPR
        !          5163:       || TREE_CODE (exp) == PREDECREMENT_EXPR)
        !          5164:     this_optab = sub_optab;
        !          5165: 
        !          5166:   /* If OP0 is not the actual lvalue, but rather a copy in a register,
        !          5167:      then we cannot just increment OP0.  We must
        !          5168:      therefore contrive to increment the original value.
        !          5169:      Then we can return OP0 since it is a copy of the old value.  */
        !          5170:   if (op0_is_copy)
        !          5171:     {
        !          5172:       /* This is the easiest way to increment the value wherever it is.
        !          5173:         Problems with multiple evaluation of INCREMENTED
        !          5174:         are prevented because either (1) it is a component_ref,
        !          5175:         in which case it was stabilized above, or (2) it is an array_ref
        !          5176:         with constant index in an array in a register, which is
        !          5177:         safe to reevaluate.  */
        !          5178:       tree newexp = build ((this_optab == add_optab
        !          5179:                            ? PLUS_EXPR : MINUS_EXPR),
        !          5180:                           TREE_TYPE (exp),
        !          5181:                           incremented,
        !          5182:                           TREE_OPERAND (exp, 1));
        !          5183:       temp = expand_assignment (incremented, newexp, ! post, 0);
        !          5184:       return post ? op0 : temp;
        !          5185:     }
        !          5186: 
        !          5187:   /* Convert decrement by a constant into a negative increment.  */
        !          5188:   if (this_optab == sub_optab
        !          5189:       && GET_CODE (op1) == CONST_INT)
        !          5190:     {
        !          5191:       op1 = gen_rtx (CONST_INT, VOIDmode, - INTVAL (op1));
        !          5192:       this_optab = add_optab;
        !          5193:     }
        !          5194: 
        !          5195:   if (post)
        !          5196:     {
        !          5197:       /* We have a true reference to the value in OP0.
        !          5198:         If there is an insn to add or subtract in this mode, queue it.  */
        !          5199: 
        !          5200: #if 0  /* Turned off to avoid making extra insn for indexed memref.  */
        !          5201:       op0 = stabilize (op0);
        !          5202: #endif
        !          5203: 
        !          5204:       icode = (int) this_optab->handlers[(int) mode].insn_code;
        !          5205:       if (icode != (int) CODE_FOR_nothing
        !          5206:          /* Make sure that OP0 is valid for operands 0 and 1
        !          5207:             of the insn we want to queue.  */
        !          5208:          && (*insn_operand_predicate[icode][0]) (op0, mode)
        !          5209:          && (*insn_operand_predicate[icode][1]) (op0, mode))
        !          5210:        {
        !          5211:          if (! (*insn_operand_predicate[icode][2]) (op1, mode))
        !          5212:            op1 = force_reg (mode, op1);
        !          5213: 
        !          5214:          return enqueue_insn (op0, GEN_FCN (icode) (op0, op0, op1));
        !          5215:        }
        !          5216:     }
        !          5217: 
        !          5218:   /* Preincrement, or we can't increment with one simple insn.  */
        !          5219:   if (post)
        !          5220:     /* Save a copy of the value before inc or dec, to return it later.  */
        !          5221:     temp = value = copy_to_reg (op0);
        !          5222:   else
        !          5223:     /* Arrange to return the incremented value.  */
        !          5224:     /* Copy the rtx because expand_binop will protect from the queue,
        !          5225:        and the results of that would be invalid for us to return
        !          5226:        if our caller does emit_queue before using our result.  */
        !          5227:     temp = copy_rtx (value = op0);
        !          5228: 
        !          5229:   /* Increment however we can.  */
        !          5230:   op1 = expand_binop (mode, this_optab, value, op1, op0,
        !          5231:                      TREE_UNSIGNED (TREE_TYPE (exp)), OPTAB_LIB_WIDEN);
        !          5232:   /* Make sure the value is stored into OP0.  */
        !          5233:   if (op1 != op0)
        !          5234:     emit_move_insn (op0, op1);
        !          5235: 
        !          5236:   return temp;
        !          5237: }
        !          5238: 
        !          5239: /* Expand all function calls contained within EXP, innermost ones first.
        !          5240:    But don't look within expressions that have sequence points.
        !          5241:    For each CALL_EXPR, record the rtx for its value
        !          5242:    in the CALL_EXPR_RTL field.  */
        !          5243: 
        !          5244: static void
        !          5245: preexpand_calls (exp)
        !          5246:      tree exp;
        !          5247: {
        !          5248:   register int nops, i;
        !          5249:   int type = TREE_CODE_CLASS (TREE_CODE (exp));
        !          5250: 
        !          5251:   if (! do_preexpand_calls)
        !          5252:     return;
        !          5253: 
        !          5254:   /* Only expressions and references can contain calls.  */
        !          5255: 
        !          5256:   if (type != 'e' && type != '<' && type != '1' && type != '2' && type != 'r')
        !          5257:     return;
        !          5258: 
        !          5259:   switch (TREE_CODE (exp))
        !          5260:     {
        !          5261:     case CALL_EXPR:
        !          5262:       /* Do nothing if already expanded.  */
        !          5263:       if (CALL_EXPR_RTL (exp) != 0)
        !          5264:        return;
        !          5265: 
        !          5266:       /* Do nothing to built-in functions.  */
        !          5267:       if (TREE_CODE (TREE_OPERAND (exp, 0)) != ADDR_EXPR
        !          5268:          || TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) != FUNCTION_DECL
        !          5269:          || ! DECL_BUILT_IN (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
        !          5270:        CALL_EXPR_RTL (exp) = expand_call (exp, 0, 0, 0);
        !          5271:       return;
        !          5272: 
        !          5273:     case COMPOUND_EXPR:
        !          5274:     case COND_EXPR:
        !          5275:     case TRUTH_ANDIF_EXPR:
        !          5276:     case TRUTH_ORIF_EXPR:
        !          5277:       /* If we find one of these, then we can be sure
        !          5278:         the adjust will be done for it (since it makes jumps).
        !          5279:         Do it now, so that if this is inside an argument
        !          5280:         of a function, we don't get the stack adjustment
        !          5281:         after some other args have already been pushed.  */
        !          5282:       do_pending_stack_adjust ();
        !          5283:       return;
        !          5284: 
        !          5285:     case BLOCK:
        !          5286:     case RTL_EXPR:
        !          5287:     case WITH_CLEANUP_EXPR:
        !          5288:       return;
        !          5289: 
        !          5290:     case SAVE_EXPR:
        !          5291:       if (SAVE_EXPR_RTL (exp) != 0)
        !          5292:        return;
        !          5293:     }
        !          5294: 
        !          5295:   nops = tree_code_length[(int) TREE_CODE (exp)];
        !          5296:   for (i = 0; i < nops; i++)
        !          5297:     if (TREE_OPERAND (exp, i) != 0)
        !          5298:       {
        !          5299:        type = TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, i)));
        !          5300:        if (type == 'e' || type == '<' || type == '1' || type == '2'
        !          5301:            || type == 'r')
        !          5302:          preexpand_calls (TREE_OPERAND (exp, i));
        !          5303:       }
        !          5304: }
        !          5305: 
        !          5306: /* At the start of a function, record that we have no previously-pushed
        !          5307:    arguments waiting to be popped.  */
        !          5308: 
        !          5309: void
        !          5310: init_pending_stack_adjust ()
        !          5311: {
        !          5312:   pending_stack_adjust = 0;
        !          5313: }
        !          5314: 
        !          5315: /* When exiting from function, if safe, clear out any pending stack adjust
        !          5316:    so the adjustment won't get done.  */
        !          5317: 
        !          5318: void
        !          5319: clear_pending_stack_adjust ()
        !          5320: {
        !          5321: #ifdef EXIT_IGNORE_STACK
        !          5322:   if (!flag_omit_frame_pointer && EXIT_IGNORE_STACK
        !          5323:       && ! (TREE_INLINE (current_function_decl) && optimize)
        !          5324:       && ! flag_inline_functions)
        !          5325:     pending_stack_adjust = 0;
        !          5326: #endif
        !          5327: }
        !          5328: 
        !          5329: /* Pop any previously-pushed arguments that have not been popped yet.  */
        !          5330: 
        !          5331: void
        !          5332: do_pending_stack_adjust ()
        !          5333: {
        !          5334:   if (inhibit_defer_pop == 0)
        !          5335:     {
        !          5336:       if (pending_stack_adjust != 0)
        !          5337:        adjust_stack (gen_rtx (CONST_INT, VOIDmode, pending_stack_adjust));
        !          5338:       pending_stack_adjust = 0;
        !          5339:     }
        !          5340: }
        !          5341: 
        !          5342: /* Expand all cleanups up to OLD_CLEANUPS.
        !          5343:    Needed here, and also for language-dependent calls.  */
        !          5344: 
        !          5345: void
        !          5346: expand_cleanups_to (old_cleanups)
        !          5347:      tree old_cleanups;
        !          5348: {
        !          5349:   while (cleanups_this_call != old_cleanups)
        !          5350:     {
        !          5351:       expand_expr (TREE_VALUE (cleanups_this_call), 0, VOIDmode, 0);
        !          5352:       cleanups_this_call = TREE_CHAIN (cleanups_this_call);
        !          5353:     }
        !          5354: }
        !          5355: 
        !          5356: /* Expand conditional expressions.  */
        !          5357: 
        !          5358: /* Generate code to evaluate EXP and jump to LABEL if the value is zero.
        !          5359:    LABEL is an rtx of code CODE_LABEL, in this function and all the
        !          5360:    functions here.  */
        !          5361: 
        !          5362: void
        !          5363: jumpifnot (exp, label)
        !          5364:      tree exp;
        !          5365:      rtx label;
        !          5366: {
        !          5367:   do_jump (exp, label, 0);
        !          5368: }
        !          5369: 
        !          5370: /* Generate code to evaluate EXP and jump to LABEL if the value is nonzero.  */
        !          5371: 
        !          5372: void
        !          5373: jumpif (exp, label)
        !          5374:      tree exp;
        !          5375:      rtx label;
        !          5376: {
        !          5377:   do_jump (exp, 0, label);
        !          5378: }
        !          5379: 
        !          5380: /* Generate code to evaluate EXP and jump to IF_FALSE_LABEL if
        !          5381:    the result is zero, or IF_TRUE_LABEL if the result is one.
        !          5382:    Either of IF_FALSE_LABEL and IF_TRUE_LABEL may be zero,
        !          5383:    meaning fall through in that case.
        !          5384: 
        !          5385:    This function is responsible for optimizing cases such as
        !          5386:    &&, || and comparison operators in EXP.  */
        !          5387: 
        !          5388: void
        !          5389: do_jump (exp, if_false_label, if_true_label)
        !          5390:      tree exp;
        !          5391:      rtx if_false_label, if_true_label;
        !          5392: {
        !          5393:   register enum tree_code code = TREE_CODE (exp);
        !          5394:   /* Some cases need to create a label to jump to
        !          5395:      in order to properly fall through.
        !          5396:      These cases set DROP_THROUGH_LABEL nonzero.  */
        !          5397:   rtx drop_through_label = 0;
        !          5398:   rtx temp;
        !          5399:   rtx comparison = 0;
        !          5400:   int i;
        !          5401:   tree type;
        !          5402: 
        !          5403:   emit_queue ();
        !          5404: 
        !          5405:   switch (code)
        !          5406:     {
        !          5407:     case ERROR_MARK:
        !          5408:       break;
        !          5409: 
        !          5410:     case INTEGER_CST:
        !          5411:       temp = integer_zerop (exp) ? if_false_label : if_true_label;
        !          5412:       if (temp)
        !          5413:        emit_jump (temp);
        !          5414:       break;
        !          5415: 
        !          5416: #if 0
        !          5417:       /* This is not true with #pragma weak  */
        !          5418:     case ADDR_EXPR:
        !          5419:       /* The address of something can never be zero.  */
        !          5420:       if (if_true_label)
        !          5421:        emit_jump (if_true_label);
        !          5422:       break;
        !          5423: #endif
        !          5424: 
        !          5425:     case NOP_EXPR:
        !          5426:       if (TREE_CODE (TREE_OPERAND (exp, 0)) == COMPONENT_REF
        !          5427:          || TREE_CODE (TREE_OPERAND (exp, 0)) == BIT_FIELD_REF
        !          5428:          || TREE_CODE (TREE_OPERAND (exp, 0)) == ARRAY_REF)
        !          5429:        goto normal;
        !          5430:     case CONVERT_EXPR:
        !          5431:       /* If we are narrowing the operand, we have to do the compare in the
        !          5432:         narrower mode.  */
        !          5433:       if ((TYPE_PRECISION (TREE_TYPE (exp))
        !          5434:           < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0)))))
        !          5435:        goto normal;
        !          5436:     case NON_LVALUE_EXPR:
        !          5437:     case REFERENCE_EXPR:
        !          5438:     case ABS_EXPR:
        !          5439:     case NEGATE_EXPR:
        !          5440:     case LROTATE_EXPR:
        !          5441:     case RROTATE_EXPR:
        !          5442:       /* These cannot change zero->non-zero or vice versa.  */
        !          5443:       do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
        !          5444:       break;
        !          5445: 
        !          5446: #if 0
        !          5447:       /* This is never less insns than evaluating the PLUS_EXPR followed by
        !          5448:         a test and can be longer if the test is eliminated.  */
        !          5449:     case PLUS_EXPR:
        !          5450:       /* Reduce to minus.  */
        !          5451:       exp = build (MINUS_EXPR, TREE_TYPE (exp),
        !          5452:                   TREE_OPERAND (exp, 0),
        !          5453:                   fold (build1 (NEGATE_EXPR, TREE_TYPE (TREE_OPERAND (exp, 1)),
        !          5454:                                 TREE_OPERAND (exp, 1))));
        !          5455:       /* Process as MINUS.  */
        !          5456: #endif
        !          5457: 
        !          5458:     case MINUS_EXPR:
        !          5459:       /* Non-zero iff operands of minus differ.  */
        !          5460:       comparison = compare (build (NE_EXPR, TREE_TYPE (exp),
        !          5461:                                   TREE_OPERAND (exp, 0),
        !          5462:                                   TREE_OPERAND (exp, 1)),
        !          5463:                            NE, NE);
        !          5464:       break;
        !          5465: 
        !          5466:     case BIT_AND_EXPR:
        !          5467:       /* If we are AND'ing with a small constant, do this comparison in the
        !          5468:         smallest type that fits.  If the machine doesn't have comparisons
        !          5469:         that small, it will be converted back to the wider comparison.
        !          5470:         This helps if we are testing the sign bit of a narrower object.
        !          5471:         combine can't do this for us because it can't know whether a
        !          5472:         ZERO_EXTRACT or a compare in a smaller mode exists, but we do.  */
        !          5473: 
        !          5474:       if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
        !          5475:          && TYPE_PRECISION (TREE_TYPE (exp)) <= HOST_BITS_PER_INT
        !          5476:          && (i = floor_log2 (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)))) >= 0
        !          5477:          && (type = type_for_size (i + 1, 1)) != 0
        !          5478:          && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (exp)))
        !          5479:        {
        !          5480:          do_jump (convert (type, exp), if_false_label, if_true_label);
        !          5481:          break;
        !          5482:        }
        !          5483:       goto normal;
        !          5484: 
        !          5485:     case TRUTH_NOT_EXPR:
        !          5486:       do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label);
        !          5487:       break;
        !          5488: 
        !          5489:     case TRUTH_ANDIF_EXPR:
        !          5490:       if (if_false_label == 0)
        !          5491:        if_false_label = drop_through_label = gen_label_rtx ();
        !          5492:       do_jump (TREE_OPERAND (exp, 0), if_false_label, 0);
        !          5493:       do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
        !          5494:       break;
        !          5495: 
        !          5496:     case TRUTH_ORIF_EXPR:
        !          5497:       if (if_true_label == 0)
        !          5498:        if_true_label = drop_through_label = gen_label_rtx ();
        !          5499:       do_jump (TREE_OPERAND (exp, 0), 0, if_true_label);
        !          5500:       do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
        !          5501:       break;
        !          5502: 
        !          5503:     case COMPOUND_EXPR:
        !          5504:       expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0);
        !          5505:       free_temp_slots ();
        !          5506:       emit_queue ();
        !          5507:       do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
        !          5508:       break;
        !          5509: 
        !          5510:     case COMPONENT_REF:
        !          5511:     case BIT_FIELD_REF:
        !          5512:     case ARRAY_REF:
        !          5513:       {
        !          5514:        int bitsize, bitpos, unsignedp;
        !          5515:        enum machine_mode mode;
        !          5516:        tree type;
        !          5517:        int volatilep = 0;
        !          5518: 
        !          5519:        /* Get description of this reference.  We don't actually care
        !          5520:           about the underlying object here.  */
        !          5521:        get_inner_reference (exp, &bitsize, &bitpos, &mode, &unsignedp,
        !          5522:                             &volatilep);
        !          5523: 
        !          5524:        type = type_for_size (bitsize, unsignedp);
        !          5525:        if (type != 0
        !          5526:            && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (exp)))
        !          5527:          {
        !          5528:            do_jump (convert (type, exp), if_false_label, if_true_label);
        !          5529:            break;
        !          5530:          }
        !          5531:        goto normal;
        !          5532:       }
        !          5533: 
        !          5534:     case COND_EXPR:
        !          5535:       /* Do (a ? 1 : 0) and (a ? 0 : 1) as special cases.  */
        !          5536:       if (integer_onep (TREE_OPERAND (exp, 1))
        !          5537:          && integer_zerop (TREE_OPERAND (exp, 2)))
        !          5538:        do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
        !          5539: 
        !          5540:       else if (integer_zerop (TREE_OPERAND (exp, 1))
        !          5541:               && integer_onep (TREE_OPERAND (exp, 2)))
        !          5542:        do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label);
        !          5543: 
        !          5544:       else
        !          5545:        {
        !          5546:          register rtx label1 = gen_label_rtx ();
        !          5547:          drop_through_label = gen_label_rtx ();
        !          5548:          do_jump (TREE_OPERAND (exp, 0), label1, 0);
        !          5549:          /* Now the THEN-expression.  */
        !          5550:          do_jump (TREE_OPERAND (exp, 1),
        !          5551:                   if_false_label ? if_false_label : drop_through_label,
        !          5552:                   if_true_label ? if_true_label : drop_through_label);
        !          5553:          emit_label (label1);
        !          5554:          /* Now the ELSE-expression.  */
        !          5555:          do_jump (TREE_OPERAND (exp, 2),
        !          5556:                   if_false_label ? if_false_label : drop_through_label,
        !          5557:                   if_true_label ? if_true_label : drop_through_label);
        !          5558:        }
        !          5559:       break;
        !          5560: 
        !          5561:     case EQ_EXPR:
        !          5562:       if (integer_zerop (TREE_OPERAND (exp, 1)))
        !          5563:        do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label);
        !          5564:       else if ((GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
        !          5565:                == MODE_INT)
        !          5566:               && 
        !          5567:               !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
        !          5568:        do_jump_by_parts_equality (exp, if_false_label, if_true_label);
        !          5569:       else
        !          5570:        comparison = compare (exp, EQ, EQ);
        !          5571:       break;
        !          5572: 
        !          5573:     case NE_EXPR:
        !          5574:       if (integer_zerop (TREE_OPERAND (exp, 1)))
        !          5575:        do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
        !          5576:       else if ((GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
        !          5577:                == MODE_INT)
        !          5578:               && 
        !          5579:               !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
        !          5580:        do_jump_by_parts_equality (exp, if_true_label, if_false_label);
        !          5581:       else
        !          5582:        comparison = compare (exp, NE, NE);
        !          5583:       break;
        !          5584: 
        !          5585:     case LT_EXPR:
        !          5586:       if ((GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
        !          5587:           == MODE_INT)
        !          5588:          && !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
        !          5589:        do_jump_by_parts_greater (exp, 1, if_false_label, if_true_label);
        !          5590:       else
        !          5591:        comparison = compare (exp, LT, LTU);
        !          5592:       break;
        !          5593: 
        !          5594:     case LE_EXPR:
        !          5595:       if ((GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
        !          5596:           == MODE_INT)
        !          5597:          && !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
        !          5598:        do_jump_by_parts_greater (exp, 0, if_true_label, if_false_label);
        !          5599:       else
        !          5600:        comparison = compare (exp, LE, LEU);
        !          5601:       break;
        !          5602: 
        !          5603:     case GT_EXPR:
        !          5604:       if ((GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
        !          5605:           == MODE_INT)
        !          5606:          && !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
        !          5607:        do_jump_by_parts_greater (exp, 0, if_false_label, if_true_label);
        !          5608:       else
        !          5609:        comparison = compare (exp, GT, GTU);
        !          5610:       break;
        !          5611: 
        !          5612:     case GE_EXPR:
        !          5613:       if ((GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
        !          5614:           == MODE_INT)
        !          5615:          && !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
        !          5616:        do_jump_by_parts_greater (exp, 1, if_true_label, if_false_label);
        !          5617:       else
        !          5618:        comparison = compare (exp, GE, GEU);
        !          5619:       break;
        !          5620: 
        !          5621:     default:
        !          5622:     normal:
        !          5623:       temp = expand_expr (exp, 0, VOIDmode, 0);
        !          5624: #if 0
        !          5625:       /* This is not needed any more and causes poor code since it causes
        !          5626:         comparisons and tests from non-SI objects to have different code
        !          5627:         sequences.  */
        !          5628:       /* Copy to register to avoid generating bad insns by cse
        !          5629:         from (set (mem ...) (arithop))  (set (cc0) (mem ...)).  */
        !          5630:       if (!cse_not_expected && GET_CODE (temp) == MEM)
        !          5631:        temp = copy_to_reg (temp);
        !          5632: #endif
        !          5633:       do_pending_stack_adjust ();
        !          5634:       if (GET_CODE (temp) == CONST_INT)
        !          5635:        comparison = (temp == const0_rtx ? const0_rtx : const_true_rtx);
        !          5636:       else if (GET_CODE (temp) == LABEL_REF)
        !          5637:        comparison = const_true_rtx;
        !          5638:       else if (GET_MODE_CLASS (GET_MODE (temp)) == MODE_INT
        !          5639:               && !can_compare_p (GET_MODE (temp)))
        !          5640:        /* Note swapping the labels gives us not-equal.  */
        !          5641:        do_jump_by_parts_equality_rtx (temp, if_true_label, if_false_label);
        !          5642:       else if (GET_MODE (temp) != VOIDmode)
        !          5643:        comparison = compare_from_rtx (temp, CONST0_RTX (GET_MODE (temp)),
        !          5644:                                       NE, 1, GET_MODE (temp), 0, 0);
        !          5645:       else
        !          5646:        abort ();
        !          5647:     }
        !          5648: 
        !          5649:   /* Do any postincrements in the expression that was tested.  */
        !          5650:   emit_queue ();
        !          5651: 
        !          5652:   /* If COMPARISON is nonzero here, it is an rtx that can be substituted
        !          5653:      straight into a conditional jump instruction as the jump condition.
        !          5654:      Otherwise, all the work has been done already.  */
        !          5655: 
        !          5656:   if (comparison == const_true_rtx)
        !          5657:     {
        !          5658:       if (if_true_label)
        !          5659:        emit_jump (if_true_label);
        !          5660:     }
        !          5661:   else if (comparison == const0_rtx)
        !          5662:     {
        !          5663:       if (if_false_label)
        !          5664:        emit_jump (if_false_label);
        !          5665:     }
        !          5666:   else if (comparison)
        !          5667:     do_jump_for_compare (comparison, if_false_label, if_true_label);
        !          5668: 
        !          5669:   free_temp_slots ();
        !          5670: 
        !          5671:   if (drop_through_label)
        !          5672:     emit_label (drop_through_label);
        !          5673: }
        !          5674: 
        !          5675: /* Given a comparison expression EXP for values too wide to be compared
        !          5676:    with one insn, test the comparison and jump to the appropriate label.
        !          5677:    The code of EXP is ignored; we always test GT if SWAP is 0,
        !          5678:    and LT if SWAP is 1.  */
        !          5679: 
        !          5680: static void
        !          5681: do_jump_by_parts_greater (exp, swap, if_false_label, if_true_label)
        !          5682:      tree exp;
        !          5683:      int swap;
        !          5684:      rtx if_false_label, if_true_label;
        !          5685: {
        !          5686:   rtx op0 = expand_expr (TREE_OPERAND (exp, swap), 0, VOIDmode, 0);
        !          5687:   rtx op1 = expand_expr (TREE_OPERAND (exp, !swap), 0, VOIDmode, 0);
        !          5688:   enum machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
        !          5689:   int nwords = (GET_MODE_SIZE (mode) / UNITS_PER_WORD);
        !          5690:   rtx drop_through_label = 0;
        !          5691:   int unsignedp = TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0)));
        !          5692:   int i;
        !          5693: 
        !          5694:   if (! if_true_label || ! if_false_label)
        !          5695:     drop_through_label = gen_label_rtx ();
        !          5696:   if (! if_true_label)
        !          5697:     if_true_label = drop_through_label;
        !          5698:   if (! if_false_label)
        !          5699:     if_false_label = drop_through_label;
        !          5700: 
        !          5701:   /* Compare a word at a time, high order first.  */
        !          5702:   for (i = 0; i < nwords; i++)
        !          5703:     {
        !          5704:       rtx comp;
        !          5705:       rtx op0_word, op1_word;
        !          5706: 
        !          5707:       if (WORDS_BIG_ENDIAN)
        !          5708:        {
        !          5709:          op0_word = operand_subword_force (op0, i, mode);
        !          5710:          op1_word = operand_subword_force (op1, i, mode);
        !          5711:        }
        !          5712:       else
        !          5713:        {
        !          5714:          op0_word = operand_subword_force (op0, nwords - 1 - i, mode);
        !          5715:          op1_word = operand_subword_force (op1, nwords - 1 - i, mode);
        !          5716:        }
        !          5717: 
        !          5718:       /* All but high-order word must be compared as unsigned.  */
        !          5719:       comp = compare_from_rtx (op0_word, op1_word,
        !          5720:                               (unsignedp || i > 0) ? GTU : GT,
        !          5721:                               unsignedp, word_mode, 0, 0);
        !          5722:       if (comp == const_true_rtx)
        !          5723:        emit_jump (if_true_label);
        !          5724:       else if (comp != const0_rtx)
        !          5725:        do_jump_for_compare (comp, 0, if_true_label);
        !          5726: 
        !          5727:       /* Consider lower words only if these are equal.  */
        !          5728:       comp = compare_from_rtx (op0_word, op1_word, NE, unsignedp, word_mode,
        !          5729:                               0, 0);
        !          5730:       if (comp == const_true_rtx)
        !          5731:        emit_jump (if_false_label);
        !          5732:       else if (comp != const0_rtx)
        !          5733:        do_jump_for_compare (comp, 0, if_false_label);
        !          5734:     }
        !          5735: 
        !          5736:   if (if_false_label)
        !          5737:     emit_jump (if_false_label);
        !          5738:   if (drop_through_label)
        !          5739:     emit_label (drop_through_label);
        !          5740: }
        !          5741: 
        !          5742: /* Given an EQ_EXPR expression EXP for values too wide to be compared
        !          5743:    with one insn, test the comparison and jump to the appropriate label.  */
        !          5744: 
        !          5745: static void
        !          5746: do_jump_by_parts_equality (exp, if_false_label, if_true_label)
        !          5747:      tree exp;
        !          5748:      rtx if_false_label, if_true_label;
        !          5749: {
        !          5750:   rtx op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
        !          5751:   rtx op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
        !          5752:   enum machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
        !          5753:   int nwords = (GET_MODE_SIZE (mode) / UNITS_PER_WORD);
        !          5754:   int i;
        !          5755:   rtx drop_through_label = 0;
        !          5756: 
        !          5757:   if (! if_false_label)
        !          5758:     drop_through_label = if_false_label = gen_label_rtx ();
        !          5759: 
        !          5760:   for (i = 0; i < nwords; i++)
        !          5761:     {
        !          5762:       rtx comp = compare_from_rtx (operand_subword_force (op0, i, mode),
        !          5763:                                   operand_subword_force (op1, i, mode),
        !          5764:                                   EQ, 0, word_mode, 0, 0);
        !          5765:       if (comp == const_true_rtx)
        !          5766:        emit_jump (if_false_label);
        !          5767:       else if (comp != const0_rtx)
        !          5768:        do_jump_for_compare (comp, if_false_label, 0);
        !          5769:     }
        !          5770: 
        !          5771:   if (if_true_label)
        !          5772:     emit_jump (if_true_label);
        !          5773:   if (drop_through_label)
        !          5774:     emit_label (drop_through_label);
        !          5775: }
        !          5776: 
        !          5777: /* Jump according to whether OP0 is 0.
        !          5778:    We assume that OP0 has an integer mode that is too wide
        !          5779:    for the available compare insns.  */
        !          5780: 
        !          5781: static void
        !          5782: do_jump_by_parts_equality_rtx (op0, if_false_label, if_true_label)
        !          5783:      rtx op0;
        !          5784:      rtx if_false_label, if_true_label;
        !          5785: {
        !          5786:   int nwords = GET_MODE_SIZE (GET_MODE (op0)) / UNITS_PER_WORD;
        !          5787:   int i;
        !          5788:   rtx drop_through_label = 0;
        !          5789: 
        !          5790:   if (! if_false_label)
        !          5791:     drop_through_label = if_false_label = gen_label_rtx ();
        !          5792: 
        !          5793:   for (i = 0; i < nwords; i++)
        !          5794:     {
        !          5795:       rtx comp = compare_from_rtx (operand_subword_force (op0, i,
        !          5796:                                                          GET_MODE (op0)),
        !          5797:                                   const0_rtx, EQ, 0, word_mode, 0, 0);
        !          5798:       if (comp == const_true_rtx)
        !          5799:        emit_jump (if_false_label);
        !          5800:       else if (comp != const0_rtx)
        !          5801:        do_jump_for_compare (comp, if_false_label, 0);
        !          5802:     }
        !          5803: 
        !          5804:   if (if_true_label)
        !          5805:     emit_jump (if_true_label);
        !          5806:   if (drop_through_label)
        !          5807:     emit_label (drop_through_label);
        !          5808: }
        !          5809: 
        !          5810: /* Given a comparison expression in rtl form, output conditional branches to
        !          5811:    IF_TRUE_LABEL, IF_FALSE_LABEL, or both.  */
        !          5812: 
        !          5813: static void
        !          5814: do_jump_for_compare (comparison, if_false_label, if_true_label)
        !          5815:      rtx comparison, if_false_label, if_true_label;
        !          5816: {
        !          5817:   if (if_true_label)
        !          5818:     {
        !          5819:       if (bcc_gen_fctn[(int) GET_CODE (comparison)] != 0)
        !          5820:        emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (comparison)]) (if_true_label));
        !          5821:       else
        !          5822:        abort ();
        !          5823: 
        !          5824:       if (if_false_label)
        !          5825:        emit_jump (if_false_label);
        !          5826:     }
        !          5827:   else if (if_false_label)
        !          5828:     {
        !          5829:       rtx insn;
        !          5830:       rtx prev = PREV_INSN (get_last_insn ());
        !          5831:       rtx branch = 0;
        !          5832: 
        !          5833:       /* Output the branch with the opposite condition.  Then try to invert
        !          5834:         what is generated.  If more than one insn is a branch, or if the
        !          5835:         branch is not the last insn written, abort. If we can't invert
        !          5836:         the branch, emit make a true label, redirect this jump to that,
        !          5837:         emit a jump to the false label and define the true label.  */
        !          5838: 
        !          5839:       if (bcc_gen_fctn[(int) GET_CODE (comparison)] != 0)
        !          5840:        emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (comparison)]) (if_false_label));
        !          5841:       else
        !          5842:        abort ();
        !          5843: 
        !          5844:       /* Here we get the insn before what was just emitted.
        !          5845:         On some machines, emitting the branch can discard
        !          5846:         the previous compare insn and emit a replacement.  */
        !          5847:       if (prev == 0)
        !          5848:        /* If there's only one preceding insn...  */
        !          5849:        insn = get_insns ();
        !          5850:       else
        !          5851:        insn = NEXT_INSN (prev);
        !          5852: 
        !          5853:       for (insn = NEXT_INSN (insn); insn; insn = NEXT_INSN (insn))
        !          5854:        if (GET_CODE (insn) == JUMP_INSN)
        !          5855:          {
        !          5856:            if (branch)
        !          5857:              abort ();
        !          5858:            branch = insn;
        !          5859:          }
        !          5860: 
        !          5861:       if (branch != get_last_insn ())
        !          5862:        abort ();
        !          5863: 
        !          5864:       if (! invert_jump (branch, if_false_label))
        !          5865:        {
        !          5866:          if_true_label = gen_label_rtx ();
        !          5867:          redirect_jump (branch, if_true_label);
        !          5868:          emit_jump (if_false_label);
        !          5869:          emit_label (if_true_label);
        !          5870:        }
        !          5871:     }
        !          5872: }
        !          5873: 
        !          5874: /* Generate code for a comparison expression EXP
        !          5875:    (including code to compute the values to be compared)
        !          5876:    and set (CC0) according to the result.
        !          5877:    SIGNED_CODE should be the rtx operation for this comparison for
        !          5878:    signed data; UNSIGNED_CODE, likewise for use if data is unsigned.
        !          5879: 
        !          5880:    We force a stack adjustment unless there are currently
        !          5881:    things pushed on the stack that aren't yet used.  */
        !          5882: 
        !          5883: static rtx
        !          5884: compare (exp, signed_code, unsigned_code)
        !          5885:      register tree exp;
        !          5886:      enum rtx_code signed_code, unsigned_code;
        !          5887: {
        !          5888:   register rtx op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
        !          5889:   register rtx op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
        !          5890:   register tree type = TREE_TYPE (TREE_OPERAND (exp, 0));
        !          5891:   register enum machine_mode mode = TYPE_MODE (type);
        !          5892:   int unsignedp = TREE_UNSIGNED (type);
        !          5893:   enum rtx_code code = unsignedp ? unsigned_code : signed_code;
        !          5894: 
        !          5895:   return compare_from_rtx (op0, op1, code, unsignedp, mode,
        !          5896:                           ((mode == BLKmode)
        !          5897:                            ? expr_size (TREE_OPERAND (exp, 0)) : 0),
        !          5898:                           TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
        !          5899: }
        !          5900: 
        !          5901: /* Like compare but expects the values to compare as two rtx's.
        !          5902:    The decision as to signed or unsigned comparison must be made by the caller.
        !          5903: 
        !          5904:    If MODE is BLKmode, SIZE is an RTX giving the size of the objects being
        !          5905:    compared.
        !          5906: 
        !          5907:    If ALIGN is non-zero, it is the alignment of this type; if zero, the
        !          5908:    size of MODE should be used.  */
        !          5909: 
        !          5910: rtx
        !          5911: compare_from_rtx (op0, op1, code, unsignedp, mode, size, align)
        !          5912:      register rtx op0, op1;
        !          5913:      enum rtx_code code;
        !          5914:      int unsignedp;
        !          5915:      enum machine_mode mode;
        !          5916:      rtx size;
        !          5917:      int align;
        !          5918: {
        !          5919:   /* If one operand is constant, make it the second one.  */
        !          5920: 
        !          5921:   if (GET_CODE (op0) == CONST_INT || GET_CODE (op0) == CONST_DOUBLE)
        !          5922:     {
        !          5923:       rtx tem = op0;
        !          5924:       op0 = op1;
        !          5925:       op1 = tem;
        !          5926:       code = swap_condition (code);
        !          5927:     }
        !          5928: 
        !          5929:   if (flag_force_mem)
        !          5930:     {
        !          5931:       op0 = force_not_mem (op0);
        !          5932:       op1 = force_not_mem (op1);
        !          5933:     }
        !          5934: 
        !          5935:   do_pending_stack_adjust ();
        !          5936: 
        !          5937:   if (GET_CODE (op0) == CONST_INT && GET_CODE (op1) == CONST_INT)
        !          5938:     return simplify_relational_operation (code, mode, op0, op1);
        !          5939: 
        !          5940:   /* If this is a signed equality comparison, we can do it as an
        !          5941:      unsigned comparison since zero-extension is cheaper than sign
        !          5942:      extension and comparisons with zero are done as unsigned.  If we
        !          5943:      are comparing against a constant, we must convert it to what it
        !          5944:      would look like unsigned.  */
        !          5945:   if ((code == EQ || code == NE) && ! unsignedp
        !          5946:       && GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_INT)
        !          5947:     {
        !          5948:       if (GET_CODE (op1) == CONST_INT
        !          5949:          && (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0))) != INTVAL (op1))
        !          5950:        op1 = gen_rtx (CONST_INT, VOIDmode, 
        !          5951:                       INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0)));
        !          5952:       unsignedp = 1;
        !          5953:     }
        !          5954:        
        !          5955:   emit_cmp_insn (op0, op1, code, size, mode, unsignedp, align);
        !          5956: 
        !          5957:   return gen_rtx (code, VOIDmode, cc0_rtx, const0_rtx);
        !          5958: }
        !          5959: 
        !          5960: /* Generate code to calculate EXP using a store-flag instruction
        !          5961:    and return an rtx for the result.
        !          5962:    If TARGET is nonzero, store the result there if convenient.
        !          5963: 
        !          5964:    If ONLY_CHEAP is non-zero, only do this if it is likely to be very
        !          5965:    cheap.
        !          5966: 
        !          5967:    Return zero if there is no suitable set-flag instruction
        !          5968:    available on this machine.
        !          5969: 
        !          5970:    Once expand_expr has been called on the arguments of the comparison,
        !          5971:    we are committed to doing the store flag, since it is not safe to
        !          5972:    re-evaluate the expression.  We emit the store-flag insn by calling
        !          5973:    emit_store_flag, but only expand the arguments if we have a reason
        !          5974:    to believe that emit_store_flag will be successful.  If we think that
        !          5975:    it will, but it isn't, we have to simulate the store-flag with a
        !          5976:    set/jump/set sequence.  */
        !          5977: 
        !          5978: static rtx
        !          5979: do_store_flag (exp, target, mode, only_cheap)
        !          5980:      tree exp;
        !          5981:      rtx target;
        !          5982:      enum machine_mode mode;
        !          5983:      int only_cheap;
        !          5984: {
        !          5985:   enum rtx_code code;
        !          5986:   tree arg0 = TREE_OPERAND (exp, 0);
        !          5987:   tree arg1 = TREE_OPERAND (exp, 1);
        !          5988:   tree tem;
        !          5989:   tree type = TREE_TYPE (arg0);
        !          5990:   enum machine_mode operand_mode = TYPE_MODE (type);
        !          5991:   int unsignedp = TREE_UNSIGNED (type);
        !          5992:   rtx op0, op1;
        !          5993:   enum insn_code icode;
        !          5994:   rtx subtarget = target;
        !          5995:   rtx result, label, pattern, jump_pat;
        !          5996: 
        !          5997:   /* We won't bother with BLKmode store-flag operations because it would mean
        !          5998:      passing a lot of information to emit_store_flag.  */
        !          5999:   if (operand_mode == BLKmode)
        !          6000:     return 0;
        !          6001: 
        !          6002:   while (TREE_CODE (arg0) == NON_LVALUE_EXPR)
        !          6003:     arg0 = TREE_OPERAND (arg0, 0);
        !          6004: 
        !          6005:   while (TREE_CODE (arg1) == NON_LVALUE_EXPR)
        !          6006:     arg1 = TREE_OPERAND (arg1, 0);
        !          6007: 
        !          6008:   /* Put a constant second.  */
        !          6009:   if (TREE_CODE (arg0) == REAL_CST || TREE_CODE (arg0) == INTEGER_CST)
        !          6010:     {
        !          6011:       tem = arg0; arg0 = arg1; arg1 = tem;
        !          6012:     }
        !          6013: 
        !          6014:   /* Get the rtx comparison code to use.  We know that EXP is a comparison
        !          6015:      operation of some type.  Some comparisons against 1 and -1 can be
        !          6016:      converted to comparisons with zero.  Do so here so that the tests
        !          6017:      below will be aware that we have a comparison with zero.  */
        !          6018: 
        !          6019:   switch (TREE_CODE (exp))
        !          6020:     {
        !          6021:     case EQ_EXPR:
        !          6022:       code = EQ;
        !          6023:       break;
        !          6024:     case NE_EXPR:
        !          6025:       code = NE;
        !          6026:       break;
        !          6027:     case LT_EXPR:
        !          6028:       if (integer_onep (arg1))
        !          6029:        arg1 = integer_zero_node, code = unsignedp ? LEU : LE;
        !          6030:       else
        !          6031:        code = unsignedp ? LTU : LT;
        !          6032:       break;
        !          6033:     case LE_EXPR:
        !          6034:       if (integer_all_onesp (arg1))
        !          6035:        arg1 = integer_zero_node, code = unsignedp ? LTU : LT;
        !          6036:       else
        !          6037:        code = unsignedp ? LEU : LE;
        !          6038:       break;
        !          6039:     case GT_EXPR:
        !          6040:       if (integer_all_onesp (arg1))
        !          6041:        arg1 = integer_zero_node, code = unsignedp ? GEU : GE;
        !          6042:       else
        !          6043:        code = unsignedp ? GTU : GT;
        !          6044:       break;
        !          6045:     case GE_EXPR:
        !          6046:       if (integer_onep (arg1))
        !          6047:        arg1 = integer_zero_node, code = unsignedp ? GTU : GT;
        !          6048:       else
        !          6049:        code = unsignedp ? GEU : GE;
        !          6050:       break;
        !          6051:     default:
        !          6052:       abort ();
        !          6053:     }
        !          6054: 
        !          6055:   /* If this is an equality or inequality test of a single bit, we can
        !          6056:      do this by shifting the bit being tested to the low-order bit and
        !          6057:      masking the result with the constant 1.  If the condition was EQ,
        !          6058:      we xor it with 1.  This does not require an scc insn and is faster
        !          6059:      than an scc insn even if we have it.  */
        !          6060: 
        !          6061:   if ((code == NE || code == EQ)
        !          6062:       && TREE_CODE (arg0) == BIT_AND_EXPR && integer_zerop (arg1)
        !          6063:       && integer_pow2p (TREE_OPERAND (arg0, 1))
        !          6064:       && TYPE_PRECISION (type) <= HOST_BITS_PER_INT)
        !          6065:     {
        !          6066:       int bitnum = exact_log2 (INTVAL (expand_expr (TREE_OPERAND (arg0, 1),
        !          6067:                                                    0, VOIDmode, 0)));
        !          6068: 
        !          6069:       if (subtarget == 0 || GET_CODE (subtarget) != REG
        !          6070:          || GET_MODE (subtarget) != operand_mode
        !          6071:          || ! safe_from_p (subtarget, TREE_OPERAND (arg0, 0)))
        !          6072:        subtarget = 0;
        !          6073: 
        !          6074:       op0 = expand_expr (TREE_OPERAND (arg0, 0), subtarget, VOIDmode, 0);
        !          6075: 
        !          6076:       if (bitnum != 0)
        !          6077:        op0 = expand_shift (RSHIFT_EXPR, GET_MODE (op0), op0,
        !          6078:                            size_int (bitnum), target, 1);
        !          6079: 
        !          6080:       if (GET_MODE (op0) != mode)
        !          6081:        op0 = convert_to_mode (mode, op0, 1);
        !          6082: 
        !          6083:       if (bitnum != TYPE_PRECISION (type) - 1)
        !          6084:        op0 = expand_and (op0, const1_rtx, target);
        !          6085: 
        !          6086:       if (code == EQ)
        !          6087:        op0 = expand_binop (mode, xor_optab, op0, const1_rtx, target, 0,
        !          6088:                            OPTAB_LIB_WIDEN);
        !          6089: 
        !          6090:       return op0;
        !          6091:     }
        !          6092: 
        !          6093:   /* Now see if we are likely to be able to do this.  Return if not.  */
        !          6094:   if (! can_compare_p (operand_mode))
        !          6095:     return 0;
        !          6096:   icode = setcc_gen_code[(int) code];
        !          6097:   if (icode == CODE_FOR_nothing
        !          6098:       || (only_cheap && insn_operand_mode[(int) icode][0] != mode))
        !          6099:     {
        !          6100:       /* We can only do this if it is one of the special cases that
        !          6101:         can be handled without an scc insn.  */
        !          6102:       if ((code == LT && integer_zerop (arg1))
        !          6103:          || (! only_cheap && code == GE && integer_zerop (arg1)))
        !          6104:        ;
        !          6105:       else if (BRANCH_COST >= 0
        !          6106:               && ! only_cheap && (code == NE || code == EQ)
        !          6107:               && TREE_CODE (type) != REAL_TYPE
        !          6108:               && ((abs_optab->handlers[(int) operand_mode].insn_code
        !          6109:                    != CODE_FOR_nothing)
        !          6110:                   || (ffs_optab->handlers[(int) operand_mode].insn_code
        !          6111:                       != CODE_FOR_nothing)))
        !          6112:        ;
        !          6113:       else
        !          6114:        return 0;
        !          6115:     }
        !          6116:       
        !          6117:   preexpand_calls (exp);
        !          6118:   if (subtarget == 0 || GET_CODE (subtarget) != REG
        !          6119:       || GET_MODE (subtarget) != operand_mode
        !          6120:       || ! safe_from_p (subtarget, arg1))
        !          6121:     subtarget = 0;
        !          6122: 
        !          6123:   op0 = expand_expr (arg0, subtarget, VOIDmode, 0);
        !          6124:   op1 = expand_expr (arg1, 0, VOIDmode, 0);
        !          6125: 
        !          6126:   if (target == 0)
        !          6127:     target = gen_reg_rtx (mode);
        !          6128: 
        !          6129:   result = emit_store_flag (target, code, op0, op1, operand_mode,
        !          6130:                            unsignedp, 1);
        !          6131: 
        !          6132:   if (result)
        !          6133:     return result;
        !          6134: 
        !          6135:   /* If this failed, we have to do this with set/compare/jump/set code.  */
        !          6136:   if (target == 0 || GET_CODE (target) != REG
        !          6137:       || reg_mentioned_p (target, op0) || reg_mentioned_p (target, op1))
        !          6138:     target = gen_reg_rtx (GET_MODE (target));
        !          6139: 
        !          6140:   emit_move_insn (target, const1_rtx);
        !          6141:   result = compare_from_rtx (op0, op1, code, unsignedp, operand_mode, 0, 0);
        !          6142:   if (GET_CODE (result) == CONST_INT)
        !          6143:     return result == const0_rtx ? const0_rtx : const1_rtx;
        !          6144: 
        !          6145:   label = gen_label_rtx ();
        !          6146:   if (bcc_gen_fctn[(int) code] == 0)
        !          6147:     abort ();
        !          6148: 
        !          6149:   emit_jump_insn ((*bcc_gen_fctn[(int) code]) (label));
        !          6150:   emit_move_insn (target, const0_rtx);
        !          6151:   emit_label (label);
        !          6152: 
        !          6153:   return target;
        !          6154: }
        !          6155: 
        !          6156: /* Generate a tablejump instruction (used for switch statements).  */
        !          6157: 
        !          6158: #ifdef HAVE_tablejump
        !          6159: 
        !          6160: /* INDEX is the value being switched on, with the lowest value
        !          6161:    in the table already subtracted.
        !          6162:    RANGE is the length of the jump table.
        !          6163:    TABLE_LABEL is a CODE_LABEL rtx for the table itself.
        !          6164: 
        !          6165:    DEFAULT_LABEL is a CODE_LABEL rtx to jump to if the
        !          6166:    index value is out of range.  */
        !          6167: 
        !          6168: void
        !          6169: do_tablejump (index, range, table_label, default_label)
        !          6170:      rtx index, range, table_label, default_label;
        !          6171: {
        !          6172:   register rtx temp, vector;
        !          6173: 
        !          6174:   emit_cmp_insn (range, index, LTU, 0, GET_MODE (index), 0, 0);
        !          6175:   emit_jump_insn (gen_bltu (default_label));
        !          6176:   /* If flag_force_addr were to affect this address
        !          6177:      it could interfere with the tricky assumptions made
        !          6178:      about addresses that contain label-refs,
        !          6179:      which may be valid only very near the tablejump itself.  */
        !          6180:   /* ??? The only correct use of CASE_VECTOR_MODE is the one inside the
        !          6181:      GET_MODE_SIZE, because this indicates how large insns are.  The other
        !          6182:      uses should all be Pmode, because they are addresses.  This code
        !          6183:      could fail if addresses and insns are not the same size.  */
        !          6184:   index = memory_address_noforce
        !          6185:     (CASE_VECTOR_MODE,
        !          6186:      gen_rtx (PLUS, Pmode,
        !          6187:              gen_rtx (MULT, Pmode, index,
        !          6188:                       gen_rtx (CONST_INT, VOIDmode,
        !          6189:                                GET_MODE_SIZE (CASE_VECTOR_MODE))),
        !          6190:              gen_rtx (LABEL_REF, Pmode, table_label)));
        !          6191:   temp = gen_reg_rtx (CASE_VECTOR_MODE);
        !          6192:   vector = gen_rtx (MEM, CASE_VECTOR_MODE, index);
        !          6193:   RTX_UNCHANGING_P (vector) = 1;
        !          6194:   convert_move (temp, vector, 0);
        !          6195: 
        !          6196:   emit_jump_insn (gen_tablejump (temp, table_label));
        !          6197: 
        !          6198: #ifndef CASE_VECTOR_PC_RELATIVE
        !          6199:   /* If we are generating PIC code or if the table is PC-relative, the
        !          6200:      table and JUMP_INSN must be adjacent, so don't output a BARRIER.  */
        !          6201:   if (! flag_pic)
        !          6202:     emit_barrier ();
        !          6203: #endif
        !          6204: }
        !          6205: 
        !          6206: #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.