Annotation of gcc/expr.c, revision 1.1.1.3

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