Annotation of gcc/expr.c, revision 1.1.1.2

1.1       root        1: /* Convert tree expression to rtl instructions, for GNU compiler.
1.1.1.2 ! root        2:    Copyright (C) 1988 Free Software Foundation, Inc.
1.1       root        3: 
                      4: This file is part of GNU CC.
                      5: 
                      6: GNU CC is distributed in the hope that it will be useful,
                      7: but WITHOUT ANY WARRANTY.  No author or distributor
                      8: accepts responsibility to anyone for the consequences of using it
                      9: or for whether it serves any particular purpose or works at all,
                     10: unless he says so in writing.  Refer to the GNU CC General Public
                     11: License for full details.
                     12: 
                     13: Everyone is granted permission to copy, modify and redistribute
                     14: GNU CC, but only under the conditions described in the
                     15: GNU CC General Public License.   A copy of this license is
                     16: supposed to have been given to you along with GNU CC so you
                     17: can know your rights and responsibilities.  It should be in a
                     18: file named COPYING.  Among other things, the copyright notice
                     19: and this notice must be preserved on all copies.  */
                     20: 
                     21: 
                     22: #include "config.h"
                     23: #include "rtl.h"
                     24: #include "tree.h"
1.1.1.2 ! root       25: #include "flags.h"
1.1       root       26: #include "insn-flags.h"
                     27: #include "insn-codes.h"
                     28: #include "expr.h"
1.1.1.2 ! root       29: #include "insn-config.h"
        !            30: #include "recog.h"
        !            31: #include "varargs.h"
        !            32: 
        !            33: /* Decide whether a function's arguments should be processed
        !            34:    from first to last or from last to first.  */
        !            35: 
        !            36: #ifdef STACK_GROWS_DOWNWARD
        !            37: #ifdef PUSH_ROUNDING
        !            38: #define PUSH_ARGS_REVERSED     /* If it's last to first */
        !            39: #endif
        !            40: #endif
        !            41: 
        !            42: /* Like STACK_BOUNDARY but in units of bytes, not bits.  */
        !            43: #define STACK_BYTES (STACK_BOUNDARY / BITS_PER_UNIT)
1.1       root       44: 
                     45: /* If this is nonzero, we do not bother generating VOLATILE
                     46:    around volatile memory references, and we are willing to
                     47:    output indirect addresses.  If cse is to follow, we reject
                     48:    indirect addresses so a useful potential cse is generated;
                     49:    if it is used only once, instruction combination will produce
                     50:    the same indirect address eventually.  */
                     51: int cse_not_expected;
                     52: 
                     53: /* Nonzero to generate code for all the subroutines within an
                     54:    expression before generating the upper levels of the expression.
                     55:    Nowadays this is never zero.  */
                     56: int do_preexpand_calls = 1;
                     57: 
                     58: /* Number of units that we should eventually pop off the stack.
                     59:    These are the arguments to function calls that have already returned.  */
                     60: int pending_stack_adjust;
                     61: 
                     62: /* Total size of arguments already pushed for function calls that
                     63:    have not happened yet.  Also counts 1 for each level of conditional
                     64:    expression that we are inside.  When this is nonzero,
                     65:    args passed to function calls must be popped right away
                     66:    to ensure contiguity of argument lists for future calls.  */
1.1.1.2 ! root       67: static int current_args_size;
1.1       root       68: 
1.1.1.2 ! root       69: /* Nonzero means current function may call alloca.  */
        !            70: int may_call_alloca;
        !            71: 
        !            72: rtx store_expr ();
        !            73: static void store_constructor ();
        !            74: static rtx store_field ();
1.1       root       75: static rtx expand_call ();
1.1.1.2 ! root       76: static void emit_call_1 ();
        !            77: static rtx prepare_call_address ();
        !            78: static rtx expand_builtin ();
1.1       root       79: static rtx compare ();
1.1.1.2 ! root       80: static rtx compare_constants ();
1.1       root       81: static rtx compare1 ();
                     82: static rtx do_store_flag ();
                     83: static void preexpand_calls ();
1.1.1.2 ! root       84: static rtx expand_increment ();
        !            85: static void move_by_pieces_1 ();
        !            86: static void init_queue ();
        !            87: 
        !            88: void do_pending_stack_adjust ();
1.1       root       89: 
                     90: /* MOVE_RATIO is the number of move instructions that is better than
                     91:    a block move.  */
                     92: 
                     93: #if defined (HAVE_movstrhi) || defined (HAVE_movstrsi)
                     94: #define MOVE_RATIO 2
                     95: #else
                     96: #define MOVE_RATIO 6
                     97: #endif
                     98: 
                     99: /* Table indexed by tree code giving 1 if the code is for a
                    100:    comparison operation, or anything that is most easily
                    101:    computed with a conditional branch.
                    102: 
                    103:    We include tree.def to give it the proper length.
                    104:    The contents thus created are irrelevant.
                    105:    The real contents are initialized in init_comparisons.  */
                    106: 
1.1.1.2 ! root      107: #define DEFTREECODE(SYM, NAME, TYPE, LENGTH) 0,
1.1       root      108: 
                    109: static char comparison_code[] = {
                    110: #include "tree.def"
                    111: };
                    112: #undef DEFTREECODE
                    113: 
1.1.1.2 ! root      114: /* This is run once per compilation.  */
        !           115: 
        !           116: void
1.1       root      117: init_comparisons ()
                    118: {
                    119:   comparison_code[(int) EQ_EXPR] = 1;
                    120:   comparison_code[(int) NE_EXPR] = 1;
                    121:   comparison_code[(int) LT_EXPR] = 1;
                    122:   comparison_code[(int) GT_EXPR] = 1;
                    123:   comparison_code[(int) LE_EXPR] = 1;
                    124:   comparison_code[(int) GE_EXPR] = 1;
                    125: }
1.1.1.2 ! root      126: 
        !           127: /* This is run at the start of compiling a function.  */
        !           128: 
        !           129: void
        !           130: init_expr ()
        !           131: {
        !           132:   init_queue ();
        !           133:   may_call_alloca = 0;
        !           134: }
1.1       root      135: 
                    136: /* Manage the queue of increment instructions to be output
                    137:    for POSTINCREMENT_EXPR expressions, etc.  */
                    138: 
                    139: static rtx pending_chain;
                    140: 
                    141: /* Queue up to increment (or change) VAR later.  BODY says how:
                    142:    BODY should be the same thing you would pass to emit_insn
                    143:    to increment right away.  It will go to emit_insn later on.
                    144: 
                    145:    The value is a QUEUED expression to be used in place of VAR
1.1.1.2 ! root      146:    where you want to guarantee the pre-incrementation value of VAR.  */
1.1       root      147: 
                    148: static rtx
                    149: enqueue_insn (var, body)
                    150:      rtx var, body;
                    151: {
                    152:   pending_chain = gen_rtx (QUEUED, GET_MODE (var),
                    153:                           var, 0, 0, body, pending_chain);
                    154:   return pending_chain;
                    155: }
                    156: 
                    157: /* Use protect_from_queue to convert a QUEUED expression
                    158:    into something that you can put immediately into an instruction.
                    159:    If the queued incrementation has not happened yet,
                    160:    protect_from_queue returns the variable itself.
                    161:    If the incrementation has happened, protect_from_queue returns a temp
                    162:    that contains a copy of the old value of the variable.
                    163: 
                    164:    Any time an rtx which might possibly be a QUEUED is to be put
                    165:    into an instruction, it must be passed through protect_from_queue first.
                    166:    QUEUED expressions are not meaningful in instructions.
                    167: 
                    168:    Do not pass a value through protect_from_queue and then hold
                    169:    on to it for a while before putting it in an instruction!
                    170:    If the queue is flushed in between, incorrect code will result.  */
                    171: 
                    172: rtx
                    173: protect_from_queue (x, modify)
                    174:      register rtx x;
                    175:      int modify;
                    176: {
                    177:   register RTX_CODE code = GET_CODE (x);
                    178:   if (code != QUEUED)
                    179:     {
                    180:       /* A special hack for read access to (MEM (QUEUED ...))
                    181:         to facilitate use of autoincrement.
                    182:         Make a copy of the contents of the memory location
                    183:         rather than a copy of the address.  */
                    184:       if (code == MEM && GET_CODE (XEXP (x, 0)) == QUEUED && !modify)
                    185:        {
                    186:          register rtx y = XEXP (x, 0);
                    187:          XEXP (x, 0) = QUEUED_VAR (y);
                    188:          if (QUEUED_INSN (y))
                    189:            {
                    190:              register rtx temp = gen_reg_rtx (GET_MODE (x));
                    191:              emit_insn_before (gen_move_insn (temp, x),
                    192:                                QUEUED_INSN (y));
                    193:              return temp;
                    194:            }
                    195:          return x;
                    196:        }
                    197:       /* Otherwise, recursively protect the subexpressions of all
                    198:         the kinds of rtx's that can contain a QUEUED.  */
                    199:       if (code == MEM)
                    200:        XEXP (x, 0) = protect_from_queue (XEXP (x, 0), 0);
                    201:       else if (code == PLUS || code == MULT)
                    202:        {
                    203:          XEXP (x, 0) = protect_from_queue (XEXP (x, 0), 0);
                    204:          XEXP (x, 1) = protect_from_queue (XEXP (x, 1), 0);
                    205:        }
                    206:       return x;
                    207:     }
                    208:   /* If the increment has not happened, use the variable itself.  */
                    209:   if (QUEUED_INSN (x) == 0)
                    210:     return QUEUED_VAR (x);
                    211:   /* If the increment has happened and a pre-increment copy exists,
                    212:      use that copy.  */
                    213:   if (QUEUED_COPY (x) != 0)
                    214:     return QUEUED_COPY (x);
                    215:   /* The increment has happened but we haven't set up a pre-increment copy.
                    216:      Set one up now, and use it.  */
                    217:   QUEUED_COPY (x) = gen_reg_rtx (GET_MODE (QUEUED_VAR (x)));
                    218:   emit_insn_before (gen_move_insn (QUEUED_COPY (x), QUEUED_VAR (x)),
                    219:                    QUEUED_INSN (x));
                    220:   return QUEUED_COPY (x);
                    221: }
                    222: 
1.1.1.2 ! root      223: /* Return nonzero if X contains a QUEUED expression:
        !           224:    if it contains anything that will be altered by a queued increment.  */
        !           225: 
        !           226: static int
        !           227: queued_subexp_p (x)
        !           228:      rtx x;
        !           229: {
        !           230:   register enum rtx_code code = GET_CODE (x);
        !           231:   switch (code)
        !           232:     {
        !           233:     case QUEUED:
        !           234:       return 1;
        !           235:     case MEM:
        !           236:       return queued_subexp_p (XEXP (x, 0));
        !           237:     case MULT:
        !           238:     case PLUS:
        !           239:     case MINUS:
        !           240:       return queued_subexp_p (XEXP (x, 0))
        !           241:        || queued_subexp_p (XEXP (x, 1));
        !           242:     }
        !           243:   return 0;
        !           244: }
        !           245: 
        !           246: /* Perform all the pending incrementations.  */
1.1       root      247: 
                    248: void
                    249: emit_queue ()
                    250: {
                    251:   register rtx p;
                    252:   while (p = pending_chain)
                    253:     {
                    254:       QUEUED_INSN (p) = emit_insn (QUEUED_BODY (p));
                    255:       pending_chain = QUEUED_NEXT (p);
                    256:     }
                    257: }
                    258: 
1.1.1.2 ! root      259: static void
1.1       root      260: init_queue ()
                    261: {
                    262:   if (pending_chain)
                    263:     abort ();
                    264: }
                    265: 
                    266: /* Copy data from FROM to TO, where the machine modes are not the same.
                    267:    Both modes may be integer, or both may be floating.
                    268:    UNSIGNEDP should be nonzero if FROM is an unsigned type.
                    269:    This causes zero-extension instead of sign-extension.  */
                    270: 
                    271: void
                    272: convert_move (to, from, unsignedp)
                    273:      register rtx to, from;
                    274:      int unsignedp;
                    275: {
                    276:   enum machine_mode to_mode = GET_MODE (to);
                    277:   enum machine_mode from_mode = GET_MODE (from);
                    278:   int to_real = to_mode == SFmode || to_mode == DFmode;
                    279:   int from_real = from_mode == SFmode || from_mode == DFmode;
                    280:   int extending = (int) to_mode > (int) from_mode;
                    281: 
                    282:   to = protect_from_queue (to, 1);
                    283:   from = protect_from_queue (from, 0);
                    284: 
                    285:   if (to_real != from_real)
                    286:     abort ();
                    287: 
1.1.1.2 ! root      288:   if (to_mode == from_mode
        !           289:       || (from_mode == VOIDmode && CONSTANT_P (from)))
1.1       root      290:     {
                    291:       emit_move_insn (to, from);
                    292:       return;
                    293:     }
                    294: 
                    295:   if (to_real)
                    296:     {
                    297: #ifdef HAVE_extendsfdf2
                    298:       if (HAVE_extendsfdf2 && extending)
                    299:        {
1.1.1.2 ! root      300:          emit_unop_insn (CODE_FOR_extendsfdf2, to, from, UNKNOWN);
1.1       root      301:          return;
                    302:        }
                    303: #endif
                    304: #ifdef HAVE_truncdfsf2
                    305:       if (HAVE_truncdfsf2 && ! extending)
                    306:        {
1.1.1.2 ! root      307:          emit_unop_insn (CODE_FOR_truncdfsf2, to, from, UNKNOWN);
1.1       root      308:          return;
                    309:        }
                    310: #endif
                    311:       emit_library_call (gen_rtx (SYMBOL_REF, Pmode, (extending
1.1.1.2 ! root      312:                                                      ? "_extendsfdf2"
        !           313:                                                      : "_truncdfsf2")),
        !           314:                         GET_MODE (to), 1,
        !           315:                         from,  (extending ? SFmode : DFmode));
        !           316:       emit_move_insn (to, hard_libcall_value (GET_MODE (to)));
1.1       root      317:       return;
                    318:     }
                    319: 
1.1.1.2 ! root      320:   /* Now both modes are integers.  */
        !           321: 
1.1       root      322:   if (to_mode == DImode)
                    323:     {
                    324:       emit_insn (gen_rtx (CLOBBER, VOIDmode, to));
                    325: 
                    326:       if (unsignedp)
                    327:        {
                    328:          convert_move (gen_lowpart (SImode, to), from, unsignedp);
                    329:          emit_clr_insn (gen_highpart (SImode, to));
                    330:        }
1.1.1.2 ! root      331: #ifdef HAVE_slt
        !           332:       else if (HAVE_slt && insn_operand_mode[(int) CODE_FOR_slt][0] == SImode)
1.1       root      333:        {
                    334:          convert_move (gen_lowpart (SImode, to), from, unsignedp);
1.1.1.2 ! root      335:          emit_insn (gen_slt (gen_highpart (SImode, to)));
1.1       root      336:        }
                    337: #endif
                    338:       else
                    339:        {
                    340:          register rtx label = gen_label_rtx ();
                    341: 
                    342:          emit_clr_insn (gen_highpart (SImode, to));
                    343:          convert_move (gen_lowpart (SImode, to), from, unsignedp);
                    344:          emit_cmp_insn (gen_lowpart (SImode, to),
                    345:                         gen_rtx (CONST_INT, VOIDmode, 0),
                    346:                         0, 0);
                    347:          emit_jump_insn (gen_bge (label));
                    348:          expand_unop (SImode, one_cmpl_optab,
                    349:                       gen_highpart (SImode, to), gen_highpart (SImode, to),
                    350:                       1);
                    351:          emit_label (label);
                    352:        }
                    353:       return;
                    354:     }
                    355: 
                    356:   if (from_mode == DImode)
                    357:     {
                    358:       convert_move (to, gen_lowpart (SImode, from), 0);
                    359:       return;
                    360:     }
                    361: 
                    362:   /* Now follow all the conversions between integers
                    363:      no more than a word long.  */
                    364: 
1.1.1.2 ! root      365:   /* For truncation, usually we can just refer to FROM in a narrower mode.  */
        !           366:   if (GET_MODE_BITSIZE (to_mode) < GET_MODE_BITSIZE (from_mode)
        !           367:       && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (to_mode),
        !           368:                                GET_MODE_BITSIZE (from_mode))
        !           369:       && ((GET_CODE (from) == MEM
        !           370:           && ! mode_dependent_address_p (XEXP (from, 0)))
        !           371:          || GET_CODE (from) == REG))
        !           372:     {
        !           373:       emit_move_insn (to, gen_lowpart (to_mode, from));
        !           374:       return;
        !           375:     }
        !           376: 
1.1       root      377:   if (to_mode == SImode && from_mode == HImode)
                    378:     {
                    379:       if (unsignedp)
                    380:        {
                    381: #ifdef HAVE_zero_extendhisi2
                    382:          if (HAVE_zero_extendhisi2)
1.1.1.2 ! root      383:            emit_unop_insn (CODE_FOR_zero_extendhisi2, to, from, ZERO_EXTEND);
1.1       root      384:          else
                    385: #endif
                    386:            abort ();
                    387:        }
                    388:       else
                    389:        {
                    390: #ifdef HAVE_extendhisi2
                    391:          if (HAVE_extendhisi2)
1.1.1.2 ! root      392:            emit_unop_insn (CODE_FOR_extendhisi2, to, from, SIGN_EXTEND);
1.1       root      393:          else
                    394: #endif
                    395:            abort ();
                    396:        }
                    397:       return;
                    398:     }
                    399: 
                    400:   if (to_mode == SImode && from_mode == QImode)
                    401:     {
                    402:       if (unsignedp)
                    403:        {
                    404: #ifdef HAVE_zero_extendqisi2
                    405:          if (HAVE_zero_extendqisi2)
                    406:            {
1.1.1.2 ! root      407:              emit_unop_insn (CODE_FOR_zero_extendqisi2, to, from, ZERO_EXTEND);
1.1       root      408:              return;
                    409:            }
                    410: #endif
                    411: #if defined (HAVE_zero_extendqihi2) && defined (HAVE_extendhisi2)
                    412:          if (HAVE_zero_extendqihi2 && HAVE_extendhisi2)
                    413:            {
                    414:              register rtx temp = gen_reg_rtx (HImode);
1.1.1.2 ! root      415:              emit_unop_insn (CODE_FOR_zero_extendqihi2, temp, from, ZERO_EXTEND);
        !           416:              emit_unop_insn (CODE_FOR_extendhisi2, to, temp, SIGN_EXTEND);
1.1       root      417:              return;
                    418:            }
                    419: #endif
                    420:        }
                    421:       else
                    422:        {
                    423: #ifdef HAVE_extendqisi2
                    424:          if (HAVE_extendqisi2)
                    425:            {
1.1.1.2 ! root      426:              emit_unop_insn (CODE_FOR_extendqisi2, to, from, SIGN_EXTEND);
1.1       root      427:              return;
                    428:            }
                    429: #endif
                    430: #if defined (HAVE_extendqihi2) && defined (HAVE_extendhisi2)
                    431:          if (HAVE_extendqihi2 && HAVE_extendhisi2)
                    432:            {
                    433:              register rtx temp = gen_reg_rtx (HImode);
1.1.1.2 ! root      434:              emit_unop_insn (CODE_FOR_extendqihi2, temp, from, SIGN_EXTEND);
        !           435:              emit_unop_insn (CODE_FOR_extendhisi2, to, temp, SIGN_EXTEND);
1.1       root      436:              return;
                    437:            }
                    438: #endif
                    439:        }
                    440:       abort ();
                    441:     }
                    442: 
                    443:   if (to_mode == HImode && from_mode == QImode)
                    444:     {
                    445:       if (unsignedp)
                    446:        {
                    447: #ifdef HAVE_zero_extendqihi2
                    448:          if (HAVE_zero_extendqihi2)
                    449:            {
1.1.1.2 ! root      450:              emit_unop_insn (CODE_FOR_zero_extendqihi2, to, from, ZERO_EXTEND);
1.1       root      451:              return;
                    452:            }
                    453: #endif
                    454:        }
                    455:       else
                    456:        {
                    457: #ifdef HAVE_extendqihi2
                    458:          if (HAVE_extendqihi2)
                    459:            {
1.1.1.2 ! root      460:              emit_unop_insn (CODE_FOR_extendqihi2, to, from, SIGN_EXTEND);
1.1       root      461:              return;
                    462:            }
                    463: #endif
                    464:        }
                    465:       abort ();
                    466:     }
                    467: 
                    468:   /* Now we are truncating an integer to a smaller one.
                    469:      If the result is a temporary, we might as well just copy it,
                    470:      since only the low-order part of the result needs to be valid
                    471:      and it is valid with no change.  */
                    472: 
                    473:   if (GET_CODE (to) == REG)
                    474:     {
                    475:       if (GET_CODE (from) == REG)
                    476:        {
                    477:          emit_move_insn (to, gen_lowpart (GET_MODE (to), from));
                    478:          return;
                    479:        }
1.1.1.2 ! root      480:       else if (GET_CODE (from) == SUBREG)
        !           481:        {
        !           482:          from = copy_rtx (from);
        !           483:          /* This is safe since FROM is not more than one word.  */
        !           484:          PUT_MODE (from, GET_MODE (to));
        !           485:          emit_move_insn (to, from);
        !           486:          return;
        !           487:        }
1.1       root      488: #ifndef BYTES_BIG_ENDIAN
                    489:       else if (GET_CODE (from) == MEM)
                    490:        {
                    491:          register rtx addr = XEXP (from, 0);
1.1.1.2 ! root      492:          if (memory_address_p (GET_MODE (to), addr))
1.1       root      493:            {
                    494:              emit_move_insn (to, gen_rtx (MEM, GET_MODE (to), addr));
                    495:              return;
                    496:            }
                    497:        }
                    498: #endif /* not BYTES_BIG_ENDIAN */
                    499:     }
                    500: 
                    501:   if (from_mode == SImode && to_mode == HImode)
                    502:     {
                    503: #ifdef HAVE_truncsihi2
                    504:       if (HAVE_truncsihi2)
                    505:        {
1.1.1.2 ! root      506:          emit_unop_insn (CODE_FOR_truncsihi2, to, from, UNKNOWN);
1.1       root      507:          return;
                    508:        }
                    509: #endif
                    510:       abort ();
                    511:     }
                    512: 
                    513:   if (from_mode == SImode && to_mode == QImode)
                    514:     {
                    515: #ifdef HAVE_truncsiqi2
                    516:       if (HAVE_truncsiqi2)
                    517:        {
1.1.1.2 ! root      518:          emit_unop_insn (CODE_FOR_truncsiqi2, to, from, UNKNOWN);
1.1       root      519:          return;
                    520:        }
                    521: #endif
                    522:       abort ();
                    523:     }
                    524: 
                    525:   if (from_mode == HImode && to_mode == QImode)
                    526:     {
                    527: #ifdef HAVE_trunchiqi2
                    528:       if (HAVE_trunchiqi2)
                    529:        {
1.1.1.2 ! root      530:          emit_unop_insn (CODE_FOR_trunchiqi2, to, from, UNKNOWN);
1.1       root      531:          return;
                    532:        }
                    533: #endif
                    534:       abort ();
                    535:     }
1.1.1.2 ! root      536: 
        !           537:   /* Mode combination is not recognized.  */
        !           538:   abort ();
1.1       root      539: }
                    540: 
                    541: /* Return an rtx for a value that would result
                    542:    from converting X to mode MODE.
                    543:    Both X and MODE may be floating, or both integer.
                    544:    UNSIGNEDP is nonzero if X is an unsigned value.
                    545:    This can be done by referring to a part of X in place
                    546:    or by copying to a new temporary with conversion.  */
                    547: 
                    548: rtx
                    549: convert_to_mode (mode, x, unsignedp)
                    550:      enum machine_mode mode;
                    551:      rtx x;
                    552:      int unsignedp;
                    553: {
                    554:   register rtx temp;
                    555:   if (mode == GET_MODE (x))
                    556:     return x;
1.1.1.2 ! root      557:   if (integer_mode_p (mode)
        !           558:       && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (GET_MODE (x)))
1.1       root      559:     return gen_lowpart (mode, x);
                    560:   temp = gen_reg_rtx (mode);
                    561:   convert_move (temp, x, unsignedp);
                    562:   return temp;
                    563: }
1.1.1.2 ! root      564: 
        !           565: int
        !           566: integer_mode_p (mode)
        !           567:      enum machine_mode mode;
        !           568: {
        !           569:   return (int) mode > (int) VOIDmode && (int) mode <= (int) TImode;
        !           570: }
1.1       root      571: 
                    572: /* Generate several move instructions to copy LEN bytes
1.1.1.2 ! root      573:    from block FROM to block TO.  (These are MEM rtx's with BLKmode).
        !           574:    The caller must pass FROM and TO
1.1       root      575:     through protect_from_queue before calling.
                    576:    ALIGN (in bytes) is maximum alignment we can assume.  */
                    577: 
                    578: struct move_by_pieces
                    579: {
                    580:   rtx to;
1.1.1.2 ! root      581:   rtx to_addr;
1.1       root      582:   int autinc_to;
                    583:   int explicit_inc_to;
                    584:   rtx from;
1.1.1.2 ! root      585:   rtx from_addr;
1.1       root      586:   int autinc_from;
                    587:   int explicit_inc_from;
                    588:   int len;
                    589:   int offset;
                    590:   int reverse;
                    591: };
                    592: 
                    593: static void
1.1.1.2 ! root      594: move_by_pieces (to, from, len, align)
1.1       root      595:      rtx to, from;
                    596:      int len, align;
                    597: {
                    598:   struct move_by_pieces data;
1.1.1.2 ! root      599:   rtx to_addr = XEXP (to, 0), from_addr = XEXP (from, 0);
1.1       root      600: 
                    601:   data.offset = 0;
1.1.1.2 ! root      602:   data.to_addr = to_addr;
        !           603:   data.from_addr = from_addr;
1.1       root      604:   data.to = to;
                    605:   data.from = from;
1.1.1.2 ! root      606:   data.autinc_to
        !           607:     = (GET_CODE (to_addr) == PRE_INC || GET_CODE (to_addr) == PRE_DEC
        !           608:        || GET_CODE (to_addr) == POST_INC || GET_CODE (to_addr) == POST_DEC);
        !           609:   data.autinc_from
        !           610:     = (GET_CODE (from_addr) == PRE_INC || GET_CODE (from_addr) == PRE_DEC
        !           611:        || GET_CODE (from_addr) == POST_INC
        !           612:        || GET_CODE (from_addr) == POST_DEC);
1.1       root      613: 
                    614:   data.explicit_inc_from = 0;
                    615:   data.explicit_inc_to = 0;
1.1.1.2 ! root      616:   data.reverse
        !           617:     = (GET_CODE (to_addr) == PRE_DEC || GET_CODE (to_addr) == POST_DEC);
1.1       root      618:   if (data.reverse) data.offset = len;
                    619:   data.len = len;
                    620: 
                    621:   /* If copying requires more than two move insns,
                    622:      copy addresses to registers (to make displacements shorter)
                    623:      and use post-increment if available.  */
                    624:   if (!(data.autinc_from && data.autinc_to)
                    625:       && move_by_pieces_ninsns (len, align) > 2)
                    626:     {
                    627: #ifdef HAVE_PRE_DECREMENT
                    628:       if (data.reverse && ! data.autinc_from)
                    629:        {
1.1.1.2 ! root      630:          data.from_addr = copy_addr_to_reg (plus_constant (from_addr, len));
1.1       root      631:          data.autinc_from = 1;
                    632:          data.explicit_inc_from = -1;
                    633:        }
                    634: #endif
                    635: #ifdef HAVE_POST_INCREMENT
                    636:       if (! data.autinc_from)
                    637:        {
1.1.1.2 ! root      638:          data.from_addr = copy_addr_to_reg (from_addr);
1.1       root      639:          data.autinc_from = 1;
                    640:          data.explicit_inc_from = 1;
                    641:        }
                    642: #endif
1.1.1.2 ! root      643:       if (!data.autinc_from && CONSTANT_P (from_addr))
        !           644:        data.from_addr = copy_addr_to_reg (from_addr);
1.1       root      645: #ifdef HAVE_PRE_DECREMENT
                    646:       if (data.reverse && ! data.autinc_to)
                    647:        {
1.1.1.2 ! root      648:          data.to_addr = copy_addr_to_reg (plus_constant (to_addr, len));
1.1       root      649:          data.autinc_to = 1;
                    650:          data.explicit_inc_to = -1;
                    651:        }
                    652: #endif
                    653: #ifdef HAVE_POST_INCREMENT
                    654:       if (! data.reverse && ! data.autinc_to)
                    655:        {
1.1.1.2 ! root      656:          data.to_addr = copy_addr_to_reg (to_addr);
1.1       root      657:          data.autinc_to = 1;
                    658:          data.explicit_inc_to = 1;
                    659:        }
                    660: #endif
1.1.1.2 ! root      661:       if (!data.autinc_to && CONSTANT_P (to_addr))
        !           662:        data.to_addr = copy_addr_to_reg (to_addr);
1.1       root      663:     }
                    664: 
                    665: #ifdef STRICT_ALIGNMENT
1.1.1.2 ! root      666:   if (align > MOVE_MAX || align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT)
1.1       root      667:     align = MOVE_MAX;
                    668: #else
                    669:   align = MOVE_MAX;
                    670: #endif
                    671: 
                    672: #ifdef HAVE_movti
                    673:   if (HAVE_movti && align >= GET_MODE_SIZE (TImode))
                    674:     move_by_pieces_1 (gen_movti, TImode, &data);
                    675: #endif
                    676: #ifdef HAVE_movdi
                    677:   if (HAVE_movdi && align >= GET_MODE_SIZE (DImode))
                    678:     move_by_pieces_1 (gen_movdi, DImode, &data);
                    679: #endif
1.1.1.2 ! root      680: #ifdef HAVE_movsi
1.1       root      681:   if (align >= GET_MODE_SIZE (SImode))
                    682:     move_by_pieces_1 (gen_movsi, SImode, &data);
1.1.1.2 ! root      683: #endif
        !           684: #ifdef HAVE_movhi
        !           685:   if (HAVE_movhi && align >= GET_MODE_SIZE (HImode))
1.1       root      686:     move_by_pieces_1 (gen_movhi, HImode, &data);
1.1.1.2 ! root      687: #endif
        !           688: #ifdef HAVE_movqi
1.1       root      689:   move_by_pieces_1 (gen_movqi, QImode, &data);
1.1.1.2 ! root      690: #else
        !           691:   movqi instruction required in machine description
        !           692: #endif
1.1       root      693: }
                    694: 
                    695: /* Return number of insns required to move L bytes by pieces.
                    696:    ALIGN (in bytes) is maximum alignment we can assume.  */
                    697: 
1.1.1.2 ! root      698: static int
1.1       root      699: move_by_pieces_ninsns (l, align)
                    700:      unsigned int l;
                    701:      int align;
                    702: {
                    703:   register int n_insns = 0;
                    704: 
                    705: #ifdef STRICT_ALIGNMENT
1.1.1.2 ! root      706:   if (align > MOVE_MAX || align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT)
1.1       root      707:     align = MOVE_MAX;
                    708: #else
                    709:   align = MOVE_MAX;
                    710: #endif
                    711: 
                    712: #ifdef HAVE_movti
                    713:   if (HAVE_movti && align >= GET_MODE_SIZE (TImode))
                    714:     n_insns += l / GET_MODE_SIZE (TImode), l %= GET_MODE_SIZE (TImode);
                    715: #endif
                    716: #ifdef HAVE_movdi
                    717:   if (HAVE_movdi && align >= GET_MODE_SIZE (DImode))
                    718:     n_insns += l / GET_MODE_SIZE (DImode), l %= GET_MODE_SIZE (DImode);
                    719: #endif
1.1.1.2 ! root      720: #ifdef HAVE_movsi
1.1       root      721:   if (HAVE_movsi && align >= GET_MODE_SIZE (SImode))
                    722:     n_insns += l / GET_MODE_SIZE (SImode), l %= GET_MODE_SIZE (SImode);
1.1.1.2 ! root      723: #endif
        !           724: #ifdef HAVE_movhi
1.1       root      725:   if (HAVE_movhi && align >= GET_MODE_SIZE (HImode))
                    726:     n_insns += l / GET_MODE_SIZE (HImode), l %= GET_MODE_SIZE (HImode);
1.1.1.2 ! root      727: #endif
1.1       root      728:   n_insns += l;
                    729: 
                    730:   return n_insns;
                    731: }
                    732: 
                    733: /* Subroutine of move_by_pieces.  Move as many bytes as appropriate
                    734:    with move instructions for mode MODE.  GENFUN is the gen_... function
                    735:    to make a move insn for that mode.  DATA has all the other info.  */
                    736: 
1.1.1.2 ! root      737: static void
1.1       root      738: move_by_pieces_1 (genfun, mode, data)
                    739:      rtx (*genfun) ();
                    740:      enum machine_mode mode;
                    741:      struct move_by_pieces *data;
                    742: {
                    743:   register int size = GET_MODE_SIZE (mode);
                    744:   register rtx to1, from1;
                    745: 
1.1.1.2 ! root      746: #define add_offset(FLAG,X)  \
        !           747:    (FLAG ? (X) : plus_constant ((X), data->offset))
1.1       root      748: 
                    749:   while (data->len >= size)
                    750:     {
1.1.1.2 ! root      751:       if (data->reverse) data->offset -= size;
1.1       root      752: 
1.1.1.2 ! root      753:       to1 = change_address (data->to, mode,
        !           754:                            add_offset (data->autinc_to, data->to_addr));
        !           755:       from1 = change_address (data->from, mode,
        !           756:                              add_offset (data->autinc_from, data->from_addr));
1.1       root      757: 
                    758: #ifdef HAVE_PRE_DECREMENT
                    759:       if (data->explicit_inc_to < 0)
1.1.1.2 ! root      760:        emit_insn (gen_sub2_insn (data->to_addr,
1.1       root      761:                                  gen_rtx (CONST_INT, VOIDmode, size)));
                    762:       if (data->explicit_inc_from < 0)
1.1.1.2 ! root      763:        emit_insn (gen_sub2_insn (data->from_addr,
1.1       root      764:                                  gen_rtx (CONST_INT, VOIDmode, size)));
                    765: #endif
                    766: 
                    767:       emit_insn (genfun (to1, from1));
                    768: #ifdef HAVE_POST_INCREMENT
                    769:       if (data->explicit_inc_to > 0)
1.1.1.2 ! root      770:        emit_insn (gen_add2_insn (data->to_addr,
1.1       root      771:                                  gen_rtx (CONST_INT, VOIDmode, size)));
                    772:       if (data->explicit_inc_from > 0)
1.1.1.2 ! root      773:        emit_insn (gen_add2_insn (data->from_addr,
1.1       root      774:                                  gen_rtx (CONST_INT, VOIDmode, size)));
                    775: #endif
                    776: 
                    777:       if (! data->reverse) data->offset += size;
1.1.1.2 ! root      778: 
1.1       root      779:       data->len -= size;
                    780:     }
                    781: }
                    782: 
                    783: /* Emit code to move a block Y to a block X.
                    784:    This may be done with string-move instructions,
                    785:    with multiple scalar move instructions, or with a library call.
                    786: 
                    787:    Both X and Y must be MEM rtx's (perhaps inside VOLATILE)
                    788:    with mode BLKmode.
                    789:    SIZE is an rtx that says how long they are.
                    790:    ALIGN is the maximum alignment we can assume they have,
                    791:    measured in bytes.  */
                    792: 
                    793: static void
                    794: emit_block_move (x, y, size, align)
                    795:      rtx x, y;
                    796:      rtx size;
                    797:      int align;
                    798: {
                    799:   if (GET_MODE (x) != BLKmode)
                    800:     abort ();
                    801: 
                    802:   if (GET_MODE (y) != BLKmode)
                    803:     abort ();
                    804: 
                    805:   x = protect_from_queue (x, 1);
                    806:   y = protect_from_queue (y, 0);
                    807: 
1.1.1.2 ! root      808:   if (GET_CODE (x) != MEM)
1.1       root      809:     abort ();
1.1.1.2 ! root      810:   if (GET_CODE (y) != MEM)
1.1       root      811:     abort ();
                    812:   if (size == 0)
                    813:     abort ();
                    814: 
                    815:   if (GET_CODE (size) == CONST_INT
                    816:       && (move_by_pieces_ninsns ((unsigned) INTVAL (size), align)
                    817:          < MOVE_RATIO))
1.1.1.2 ! root      818:     move_by_pieces (x, y, INTVAL (size), align);
1.1       root      819:   else
                    820:     {
                    821: #ifdef HAVE_movstrsi
                    822:       if (HAVE_movstrsi)
                    823:        {
                    824:          emit_insn (gen_movstrsi (x, y, size));
                    825:          return;
                    826:        }
                    827: #endif
                    828: #ifdef HAVE_movstrhi
                    829:       if (HAVE_movstrhi
                    830:          && GET_CODE (size) == CONST_INT
                    831:          && ((unsigned) INTVAL (size)
                    832:              < (1 << (GET_MODE_SIZE (HImode) * BITS_PER_UNIT - 1))))
                    833:        {
                    834:          emit_insn (gen_movstrhi (x, y, size));
                    835:          return;
                    836:        }
                    837: #endif
1.1.1.2 ! root      838: 
        !           839: #ifdef TARGET_MEM_FUNCTIONS
        !           840:       emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memcpy"),
        !           841:                         VOIDmode, 3, XEXP (x, 0), Pmode,
        !           842:                         XEXP (y, 0), Pmode,
        !           843:                         size, Pmode);
        !           844: #else
1.1       root      845:       emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "bcopy"),
1.1.1.2 ! root      846:                         VOIDmode, 3, XEXP (y, 0), Pmode,
        !           847:                         XEXP (x, 0), Pmode,
1.1       root      848:                         size, Pmode);
1.1.1.2 ! root      849: #endif
        !           850:     }
        !           851: }
        !           852: 
        !           853: /* Copy all or part of a BLKmode value X into registers starting at REGNO.
        !           854:    The number of registers to be filled is NREGS.  */
        !           855: 
        !           856: static void
        !           857: move_block_to_reg (regno, x, nregs)
        !           858:      int regno;
        !           859:      rtx x;
        !           860:      int nregs;
        !           861: {
        !           862:   int i;
        !           863:   if (GET_CODE (x) == CONST_DOUBLE && x != dconst0_rtx)
        !           864:     x = force_const_double_mem (x);
        !           865:   for (i = 0; i < nregs; i++)
        !           866:     {
        !           867:       if (GET_CODE (x) == REG)
        !           868:        emit_move_insn (gen_rtx (REG, SImode, regno + i),
        !           869:                        gen_rtx (SUBREG, SImode, x, i));
        !           870:       else if (x == dconst0_rtx)
        !           871:        emit_move_insn (gen_rtx (REG, SImode, regno + i),
        !           872:                        const0_rtx);
        !           873:       else
        !           874:        emit_move_insn (gen_rtx (REG, SImode, regno + i),
        !           875:                        gen_rtx (MEM, SImode,
        !           876:                                 plus_constant (XEXP (x, 0),
        !           877:                                                i * GET_MODE_SIZE (SImode))));
        !           878:     }
        !           879: }
        !           880: 
        !           881: /* Copy all or part of a BLKmode value X out of registers starting at REGNO.
        !           882:    The number of registers to be filled is NREGS.  */
        !           883: 
        !           884: void
        !           885: move_block_from_reg (regno, x, nregs)
        !           886:      int regno;
        !           887:      rtx x;
        !           888:      int nregs;
        !           889: {
        !           890:   int i;
        !           891:   for (i = 0; i < nregs; i++)
        !           892:     {
        !           893:       if (GET_CODE (x) == REG)
        !           894:        emit_move_insn (gen_rtx (SUBREG, SImode, x, i),
        !           895:                        gen_rtx (REG, SImode, regno + i));
        !           896:       else
        !           897:        emit_move_insn (gen_rtx (MEM, SImode,
        !           898:                                 plus_constant (XEXP (x, 0),
        !           899:                                                i * GET_MODE_SIZE (SImode))),
        !           900:                        gen_rtx (REG, SImode, regno + i));
1.1       root      901:     }
                    902: }
1.1.1.2 ! root      903: 
        !           904: /* Mark NREGS consecutive regs, starting at REGNO, as being live now.  */
        !           905: 
        !           906: static void
        !           907: use_regs (regno, nregs)
        !           908:      int regno;
        !           909:      int nregs;
        !           910: {
        !           911:   int i;
        !           912:   for (i = 0; i < nregs; i++)
        !           913:     emit_insn (gen_rtx (USE, VOIDmode, gen_rtx (REG, SImode, regno + i)));
        !           914: }
1.1       root      915: 
1.1.1.2 ! root      916: /* Write zeros through the storage of OBJECT.
        !           917:    If OBJECT has BLKmode, SIZE is its length in bytes.  */
        !           918: 
        !           919: void
        !           920: clear_storage (object, size)
        !           921:      rtx object;
        !           922:      int size;
        !           923: {
        !           924:   if (GET_MODE (object) == BLKmode)
        !           925:     {
        !           926: #ifdef TARGET_MEM_FUNCTIONS
        !           927:       emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memset"),
        !           928:                         VOIDmode, 3,
        !           929:                         XEXP (object, 0), Pmode, const0_rtx, Pmode,
        !           930:                         gen_rtx (CONST_INT, VOIDmode, size), Pmode);
        !           931: #else
        !           932:       emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "bzero"),
        !           933:                         VOIDmode, 2,
        !           934:                         XEXP (object, 0), Pmode,
        !           935:                         gen_rtx (CONST_INT, VOIDmode, size), Pmode);
        !           936: #endif
        !           937:     }
        !           938:   else
        !           939:     emit_move_insn (object, const0_rtx, 0);
        !           940: }
        !           941: 
1.1       root      942: /* Generate code to copy Y into X.
                    943:    Both Y and X must have the same mode, except that
                    944:    Y can be a constant with VOIDmode.
1.1.1.2 ! root      945:    This mode cannot be BLKmode; use emit_block_move for that.
1.1       root      946: 
1.1.1.2 ! root      947:    Return the last instruction emitted.  */
        !           948: 
        !           949: rtx
1.1       root      950: emit_move_insn (x, y)
                    951:      rtx x, y;
                    952: {
                    953:   enum machine_mode mode = GET_MODE (x);
                    954:   x = protect_from_queue (x, 1);
                    955:   y = protect_from_queue (y, 0);
                    956: 
1.1.1.2 ! root      957:   if (CONSTANT_P (y) && ! LEGITIMATE_CONSTANT_P (y))
        !           958:     y = force_const_mem (mode, y);
        !           959: 
1.1       root      960:   if (mode == BLKmode)
                    961:     abort ();
1.1.1.2 ! root      962:   if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
        !           963:     return 
        !           964:       emit_insn (GEN_FCN (mov_optab->handlers[(int) mode].insn_code) (x, y));
        !           965: #if 0
        !           966:   /* It turns out you get much better optimization (in cse and flow)
        !           967:      if you define movdi and movdf instruction patterns
        !           968:      even if they must turn into multiple assembler instructions.  */
1.1       root      969:   else if (GET_MODE_SIZE (mode) >= GET_MODE_SIZE (SImode))
                    970:     {
                    971:       register int count = GET_MODE_SIZE (mode) / GET_MODE_SIZE (SImode);
                    972:       register int i;
1.1.1.2 ! root      973:       if (GET_CODE (y) == CONST_DOUBLE && y != dconst0_rtx)
        !           974:        y = force_const_double_mem (y);
1.1       root      975:       for (i = 0; i < count; i++)
                    976:        {
                    977:          rtx x1, y1;
                    978:          if (GET_CODE (x) == REG)
                    979:            x1 = gen_rtx (SUBREG, SImode, x, i);
                    980:          else
                    981:            x1 = gen_rtx (MEM, SImode,
                    982:                          memory_address (SImode,
                    983:                                          plus_constant (XEXP (x, 0),
                    984:                                                         i * GET_MODE_SIZE (SImode))));
                    985:          if (GET_CODE (y) == REG)
                    986:            y1 = gen_rtx (SUBREG, SImode, y, i);
1.1.1.2 ! root      987:          else if (y == dconst0_rtx)
        !           988:            y1 = const0_rtx;
1.1       root      989:          else
                    990:            y1 = gen_rtx (MEM, SImode,
                    991:                          memory_address (SImode,
                    992:                                          plus_constant (XEXP (y, 0),
                    993:                                                         i * GET_MODE_SIZE (SImode))));
                    994:          emit_insn (gen_movsi (protect_from_queue (x1, 1), protect_from_queue (y1, 0)));
                    995:        }
                    996:     }
1.1.1.2 ! root      997: #endif
1.1       root      998:   else
                    999:     abort ();
                   1000: }
                   1001: 
                   1002: /* Pushing data onto the stack.  */
                   1003: 
                   1004: /* Push a block of length SIZE (perhaps variable)
                   1005:    and return an rtx to address the beginning of the block.
                   1006:    Note that it is not possible for the value returned to be a QUEUED.  */
                   1007: 
                   1008: static rtx
                   1009: push_block (size)
                   1010:      rtx size;
                   1011: {
                   1012:   register rtx temp;
1.1.1.2 ! root     1013:   if (CONSTANT_P (size) || GET_CODE (size) == REG)
        !          1014:     anti_adjust_stack (size);
        !          1015:   else
        !          1016:     anti_adjust_stack (copy_to_mode_reg (Pmode, size));
1.1       root     1017:        
                   1018: #ifdef STACK_GROWS_DOWNWARD
1.1.1.2 ! root     1019:   temp = stack_pointer_rtx;
1.1       root     1020: #else
                   1021:   temp = gen_rtx (PLUS, Pmode,
1.1.1.2 ! root     1022:                  stack_pointer_rtx,
1.1       root     1023:                  size);
                   1024:   if (GET_CODE (size) != CONST_INT)
                   1025:     temp = force_operand (temp, 0);
                   1026: #endif
                   1027:   return memory_address (QImode, temp);
                   1028: }
                   1029: 
                   1030: static rtx
                   1031: gen_push_operand ()
                   1032: {
                   1033:   return gen_rtx (
                   1034: #ifdef STACK_GROWS_DOWNWARD
                   1035:                  PRE_DEC,
                   1036: #else
                   1037:                  PRE_INC,
                   1038: #endif
                   1039:                  Pmode,
1.1.1.2 ! root     1040:                  stack_pointer_rtx);
1.1       root     1041: }
                   1042: 
                   1043: /* Generate code to push X onto the stack, assuming it has mode MODE.
                   1044:    MODE is redundant except when X is a CONST_INT (since they don't
                   1045:    carry mode info).
                   1046:    SIZE is an rtx for the size of data to be copied (in bytes),
                   1047:    needed only if X is BLKmode.
1.1.1.2 ! root     1048:    ALIGN (in bytes) is maximum alignment we can assume.
        !          1049: 
        !          1050:    If PARTIAL is nonzero, then copy that many of the first words
        !          1051:    of X into registers starting with REG, and push the rest of X.
        !          1052:    The amount of space pushed is decreased by PARTIAL words,
        !          1053:    rounded *down* to a multiple of PARM_BOUNDARY.
        !          1054:    REG must be a hard register in this case.
        !          1055: 
        !          1056:    EXTRA is the amount in bytes of extra space to leave next to this arg.
        !          1057: 
        !          1058:    On a machine that lacks real push insns, ARGS_ADDR is the address of
        !          1059:    the bottom of the argument block for this call.  We use indexing off there
        !          1060:    to store the arg.  On machines with push insns, ARGS_ADDR is 0.
        !          1061: 
        !          1062:    ARGS_SO_FAR is the size of args previously pushed for this call.  */
1.1       root     1063: 
                   1064: static void
1.1.1.2 ! root     1065: emit_push_insn (x, mode, size, align, partial, reg, extra, args_addr, args_so_far)
1.1       root     1066:      register rtx x;
                   1067:      enum machine_mode mode;
                   1068:      rtx size;
                   1069:      int align;
1.1.1.2 ! root     1070:      int partial;
        !          1071:      rtx reg;
        !          1072:      int extra;
        !          1073:      rtx args_addr;
        !          1074:      rtx args_so_far;
1.1       root     1075: {
                   1076:   rtx xinner;
                   1077: 
                   1078:   xinner = x = protect_from_queue (x, 0);
                   1079: 
1.1.1.2 ! root     1080:   /* If part should go in registers, copy that part
        !          1081:      into the appropriate registers.  */
        !          1082:   if (partial > 0)
        !          1083:     move_block_to_reg (REGNO (reg), x, partial);
        !          1084: 
        !          1085: #ifdef STACK_GROWS_DOWNWARD
        !          1086:   if (extra && args_addr == 0)
        !          1087:     anti_adjust_stack (gen_rtx (CONST_INT, VOIDmode, extra));
        !          1088: #endif
1.1       root     1089: 
                   1090:   if (mode == BLKmode)
                   1091:     {
                   1092:       register rtx temp;
1.1.1.2 ! root     1093:       int used = partial * UNITS_PER_WORD;
        !          1094:       int offset = used % (PARM_BOUNDARY / BITS_PER_UNIT);
        !          1095: 
        !          1096:       used -= used % (PARM_BOUNDARY / BITS_PER_UNIT);
        !          1097: 
1.1       root     1098:       if (size == 0)
                   1099:        abort ();
                   1100: 
1.1.1.2 ! root     1101:       if (partial != 0)
        !          1102:        xinner = change_address (xinner, BLKmode,
        !          1103:                                 plus_constant (XEXP (xinner, 0), used));
        !          1104: 
        !          1105: #ifdef PUSH_ROUNDING
        !          1106:       /* Do it with several push insns if that doesn't take lots of insns
        !          1107:         and if there is no difficulty with push insns that skip bytes
        !          1108:         on the stack for alignment purposes.  */
        !          1109:       if (args_addr == 0
        !          1110:          && GET_CODE (size) == CONST_INT
        !          1111:          && args_addr == 0
        !          1112:          && (move_by_pieces_ninsns ((unsigned) INTVAL (size) - used, align)
        !          1113:              < MOVE_RATIO)
        !          1114:          && PUSH_ROUNDING (INTVAL (size)) == INTVAL (size))
        !          1115:        move_by_pieces (gen_rtx (MEM, BLKmode, gen_push_operand ()), xinner,
        !          1116:                        INTVAL (size) - used, align);
1.1       root     1117:       else
1.1.1.2 ! root     1118: #endif /* PUSH_ROUNDING */
1.1       root     1119:        {
1.1.1.2 ! root     1120:          /* Otherwise make space on the stack and copy the data
        !          1121:             to the address of that space.  */
        !          1122: 
        !          1123:          /* First deduct part put into registers from the size we need.  */
        !          1124:          if (partial != 0)
        !          1125:            {
        !          1126:              if (GET_CODE (size) == CONST_INT)
        !          1127:                size = gen_rtx (CONST_INT, VOIDmode, INTVAL (size) - used);
        !          1128:              else
        !          1129:                size = expand_binop (GET_MODE (size), sub_optab, size,
        !          1130:                                     gen_rtx (CONST_INT, VOIDmode, used),
        !          1131:                                     0, 0, OPTAB_LIB_WIDEN);
        !          1132:            }
        !          1133: 
        !          1134:          /* Get the address of the stack space.  */
        !          1135:          if (! args_addr)
        !          1136:            temp = push_block (size);
        !          1137:          else if (GET_CODE (args_so_far) == CONST_INT)
        !          1138:            temp = memory_address (BLKmode,
        !          1139:                                   plus_constant (args_addr,
        !          1140:                                                  offset + INTVAL (args_so_far)));
        !          1141:          else
        !          1142:            temp = memory_address (BLKmode,
        !          1143:                                   plus_constant (gen_rtx (PLUS, Pmode,
        !          1144:                                                           args_addr, args_so_far),
        !          1145:                                                  offset));
        !          1146: 
        !          1147: 
        !          1148:          /* TEMP is the address of the block.  Copy the data there.  */
        !          1149:          if (GET_CODE (size) == CONST_INT
        !          1150:              && (move_by_pieces_ninsns ((unsigned) INTVAL (size), align)
        !          1151:                  < MOVE_RATIO))
        !          1152:            {
        !          1153:              move_by_pieces (gen_rtx (MEM, BLKmode, temp), xinner,
        !          1154:                              INTVAL (size), align);
        !          1155:              return;
        !          1156:            }
1.1       root     1157: #ifdef HAVE_movstrsi
                   1158:          if (HAVE_movstrsi)
                   1159:            {
                   1160:              emit_insn (gen_movstrsi (gen_rtx (MEM, BLKmode, temp), x, size));
                   1161:              return;
                   1162:            }
                   1163: #endif
                   1164: #ifdef HAVE_movstrhi
                   1165:          if (HAVE_movstrhi
                   1166:              && GET_CODE (size) == CONST_INT
                   1167:              && ((unsigned) INTVAL (size)
                   1168:                  < (1 << (GET_MODE_SIZE (HImode) * BITS_PER_UNIT - 1))))
                   1169:            {
                   1170:              emit_insn (gen_movstrhi (gen_rtx (MEM, BLKmode, temp),
                   1171:                                       x, size));
                   1172:              return;
                   1173:            }
                   1174: #endif
1.1.1.2 ! root     1175: 
        !          1176:          if (reg_mentioned_p (stack_pointer_rtx, temp))
        !          1177:            {
        !          1178:              /* Correct TEMP so it holds what will be a description of
        !          1179:                 the address to copy to, valid after one arg is pushed.  */
1.1       root     1180: #ifdef STACK_GROWS_DOWNWARD
1.1.1.2 ! root     1181:              temp = plus_constant (temp, GET_MODE_SIZE (Pmode));
1.1       root     1182: #else
1.1.1.2 ! root     1183:              temp = plus_constant (temp, - GET_MODE_SIZE (Pmode));
1.1       root     1184: #endif
1.1.1.2 ! root     1185:            }
        !          1186: 
        !          1187:          /* Make current_args_size nonzero around the library call
        !          1188:             to force it to pop the bcopy-arguments right away.  */
        !          1189:          current_args_size += 1;
        !          1190: #ifdef TARGET_MEM_FUNCTIONS
        !          1191:          emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memcpy"),
        !          1192:                             VOIDmode, 3, temp, Pmode, XEXP (xinner, 0), Pmode,
        !          1193:                             size, Pmode);
        !          1194: #else
1.1       root     1195:          emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "bcopy"),
1.1.1.2 ! root     1196:                             VOIDmode, 3, XEXP (xinner, 0), Pmode, temp, Pmode,
1.1       root     1197:                             size, Pmode);
1.1.1.2 ! root     1198: #endif
        !          1199:          current_args_size -= 1;
1.1       root     1200:        }
                   1201:     }
1.1.1.2 ! root     1202:   else if (partial > 0)
1.1       root     1203:     {
1.1.1.2 ! root     1204:       int size = GET_MODE_SIZE (mode) / UNITS_PER_WORD;
        !          1205:       int i;
        !          1206:       int used = partial * UNITS_PER_WORD;
        !          1207:       /* # words of start of argument 
        !          1208:         that we must make space for but need not store.  */
        !          1209:       int skip = partial % (PARM_BOUNDARY / BITS_PER_WORD);
        !          1210:       int args_offset = INTVAL (args_so_far);
        !          1211: 
        !          1212:       /* If we make space by pushing it, we might as well push
        !          1213:         the real data.  Otherwise, we can leave SKIP nonzero
        !          1214:         and leave the space uninitialized.  */
        !          1215:       if (args_addr == 0)
        !          1216:        skip = 0;
        !          1217: 
        !          1218:       /* Deduct all the rest of PARTIAL words from SIZE in any case.
        !          1219:         This is space that we don't even allocate in the stack.  */
        !          1220:       used -= used % (PARM_BOUNDARY / BITS_PER_UNIT);
        !          1221:       size -= used / UNITS_PER_WORD;
        !          1222: 
        !          1223:       if (GET_CODE (x) == CONST_DOUBLE && x != dconst0_rtx)
        !          1224:        x = force_const_double_mem (x);
        !          1225: 
        !          1226: #ifndef PUSH_ARGS_REVERSED
        !          1227:       for (i = skip; i < size; i++)
        !          1228: #else
        !          1229:       for (i = size - 1; i >= skip; i--)
        !          1230: #endif
        !          1231:        if (GET_CODE (x) == MEM)
        !          1232:          emit_push_insn (gen_rtx (MEM, SImode,
        !          1233:                                   plus_constant (XEXP (x, 0),
        !          1234:                                                  i * UNITS_PER_WORD)),
        !          1235:                          SImode, 0, align, 0, 0, 0, args_addr,
        !          1236:                          gen_rtx (CONST_INT, VOIDmode,
        !          1237:                                   args_offset + i * UNITS_PER_WORD));
        !          1238:        else if (GET_CODE (x) == REG)
        !          1239:          emit_push_insn (gen_rtx (SUBREG, SImode, x, i),
        !          1240:                          SImode, 0, align, 0, 0, 0, args_addr,
        !          1241:                          gen_rtx (CONST_INT, VOIDmode,
        !          1242:                                   args_offset + i * UNITS_PER_WORD));
        !          1243:        else if (x == dconst0_rtx)
        !          1244:          emit_push_insn (const0_rtx,
        !          1245:                          SImode, 0, align, 0, 0, 0, args_addr,
        !          1246:                          gen_rtx (CONST_INT, VOIDmode,
        !          1247:                                   args_offset + i * UNITS_PER_WORD));
        !          1248:        else
        !          1249:          abort ();
1.1       root     1250:     }
                   1251:   else
1.1.1.2 ! root     1252:     {
        !          1253:       rtx addr;
        !          1254: #ifdef PUSH_ROUNDING
        !          1255:       if (args_addr == 0)
        !          1256:        addr = gen_push_operand ();
        !          1257:       else
        !          1258: #endif
        !          1259:        if (GET_CODE (args_so_far) == CONST_INT)
        !          1260:          addr
        !          1261:            = memory_address (mode,
        !          1262:                              plus_constant (args_addr, INTVAL (args_so_far)));
        !          1263:       else
        !          1264:        addr = memory_address (mode, gen_rtx (PLUS, Pmode, args_addr,
        !          1265:                                              args_so_far));
        !          1266: 
        !          1267:       emit_move_insn (gen_rtx (MEM, mode, addr), x);
        !          1268:     }
        !          1269: 
        !          1270: #ifndef STACK_GROWS_DOWNWARD
        !          1271:   if (extra && args_addr == 0)
        !          1272:     anti_adjust_stack (gen_rtx (CONST_INT, VOIDmode, extra));
        !          1273: #endif
1.1       root     1274: }
                   1275: 
                   1276: /* Output a library call to function FUN (a SYMBOL_REF rtx)
1.1.1.2 ! root     1277:    for a value of mode OUTMODE
1.1       root     1278:    with NARGS different arguments, passed as alternating rtx values
                   1279:    and machine_modes to convert them to.
                   1280:    The rtx values should have been passed through protect_from_queue already.  */
                   1281: 
                   1282: void
1.1.1.2 ! root     1283: emit_library_call (va_alist)
        !          1284:      va_dcl
1.1       root     1285: {
1.1.1.2 ! root     1286:   register va_list p;
1.1       root     1287:   register int args_size = 0;
                   1288:   register int argnum;
1.1.1.2 ! root     1289:   enum machine_mode outmode;
        !          1290:   int nargs;
        !          1291:   rtx fun;
        !          1292:   rtx orgfun;
        !          1293:   int inc;
        !          1294:   int count;
        !          1295:   rtx *regvec;
        !          1296:   rtx argblock = 0;
        !          1297:   CUMULATIVE_ARGS args_so_far;
        !          1298:   struct arg { rtx value; enum machine_mode mode; };
        !          1299:   struct arg *argvec;
        !          1300:   int old_args_size = current_args_size;
        !          1301: 
        !          1302:   va_start (p);
        !          1303:   orgfun = fun = va_arg (p, rtx);
        !          1304:   outmode = va_arg (p, enum machine_mode);
        !          1305:   nargs = va_arg (p, int);
        !          1306: 
        !          1307:   regvec = (rtx *) alloca (nargs * sizeof (rtx));
        !          1308: 
        !          1309:   /* Copy all the libcall-arguments out of the varargs data
        !          1310:      and into a vector ARGVEC.  */
        !          1311:   argvec = (struct arg *) alloca (nargs * sizeof (struct arg));
        !          1312:   for (count = 0; count < nargs; count++)
        !          1313:     {
        !          1314:       argvec[count].value = va_arg (p, rtx);
        !          1315:       argvec[count].mode = va_arg (p, enum machine_mode);
        !          1316:     }
        !          1317:   va_end (p);
        !          1318: 
        !          1319:   /* If we have no actual push instructions, make space for all the args
        !          1320:      right now.  */
        !          1321: #ifndef PUSH_ROUNDING
        !          1322:   INIT_CUMULATIVE_ARGS (args_so_far, (tree)0);
        !          1323:   for (count = 0; count < nargs; count++)
        !          1324:     {
        !          1325:       register enum machine_mode mode = argvec[count].mode;
        !          1326:       register rtx reg;
        !          1327:       register int partial;
        !          1328: 
        !          1329:       reg = FUNCTION_ARG (args_so_far, mode, 0, 1);
        !          1330: #ifdef FUNCTION_ARG_PARTIAL_NREGS
        !          1331:       partial = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode, 0, 1);
        !          1332: #else
        !          1333:       partial = 0;
        !          1334: #endif
        !          1335:       if (reg == 0 || partial != 0)
        !          1336:        args_size += GET_MODE_SIZE (mode);
        !          1337:       if (partial != 0)
        !          1338:        args_size -= partial * GET_MODE_SIZE (SImode);
        !          1339:       FUNCTION_ARG_ADVANCE (args_so_far, mode, 0, 1);
        !          1340:     }
        !          1341: 
        !          1342:   if (args_size != 0)
        !          1343:     argblock
        !          1344:       = push_block (round_push (gen_rtx (CONST_INT, VOIDmode, args_size)));
        !          1345: #endif
        !          1346: 
        !          1347:   INIT_CUMULATIVE_ARGS (args_so_far, (tree)0);
        !          1348: 
        !          1349: #ifdef PUSH_ARGS_REVERSED
        !          1350:   inc = -1;
        !          1351:   argnum = nargs - 1;
1.1       root     1352: #else
1.1.1.2 ! root     1353:   inc = 1;
        !          1354:   argnum = 0;
1.1       root     1355: #endif
1.1.1.2 ! root     1356:   args_size = 0;
        !          1357: 
        !          1358:   for (count = 0; count < nargs; count++, argnum += inc)
1.1       root     1359:     {
1.1.1.2 ! root     1360:       register enum machine_mode mode = argvec[argnum].mode;
        !          1361:       register rtx val = argvec[argnum].value;
        !          1362:       rtx reg;
        !          1363:       int partial;
        !          1364:       int arg_size;
        !          1365: 
1.1       root     1366:       /* Convert the arg value to the mode the library wants.  */
                   1367:       /* ??? It is wrong to do it here; must do it earlier
                   1368:         where we know the signedness of the arg.  */
                   1369:       if (GET_MODE (val) != mode && GET_MODE (val) != VOIDmode)
                   1370:        {
                   1371:          val = gen_reg_rtx (mode);
1.1.1.2 ! root     1372:          convert_move (val, argvec[argnum].value, 0);
1.1       root     1373:        }
1.1.1.2 ! root     1374:       reg = FUNCTION_ARG (args_so_far, mode, 0, 1);
        !          1375:       regvec[argnum] = reg;
        !          1376: #ifdef FUNCTION_ARG_PARTIAL_NREGS
        !          1377:       partial = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode, 0, 1);
        !          1378: #else
        !          1379:       partial = 0;
        !          1380: #endif
        !          1381: 
        !          1382:       if (reg != 0 && partial == 0)
        !          1383:        emit_move_insn (reg, val);
        !          1384:       else
        !          1385:        emit_push_insn (val, mode, 0, 0, partial, reg, 0, argblock,
        !          1386:                        gen_rtx (CONST_INT, VOIDmode, args_size));
        !          1387: 
        !          1388:       /* Compute size of stack space used by this argument.  */
        !          1389:       if (reg == 0 || partial != 0)
        !          1390:        arg_size = GET_MODE_SIZE (mode);
        !          1391:       else
        !          1392:        arg_size = 0;
        !          1393:       if (partial != 0)
        !          1394:        arg_size
        !          1395:          -= ((partial * UNITS_PER_WORD)
        !          1396:              / (PARM_BOUNDARY / BITS_PER_UNIT)
        !          1397:              * (PARM_BOUNDARY / BITS_PER_UNIT));
        !          1398: 
        !          1399:       args_size += arg_size;
        !          1400:       current_args_size += arg_size;
        !          1401:       FUNCTION_ARG_ADVANCE (args_so_far, mode, 0, 1);
1.1       root     1402:     }
                   1403: 
                   1404:   emit_queue ();
1.1.1.2 ! root     1405: 
        !          1406:   fun = prepare_call_address (fun, 0);
        !          1407: 
        !          1408:   /* Any regs containing parms remain in use through the call.
        !          1409:      ??? This is not quite correct, since it doesn't indicate
        !          1410:      that they are in use immediately before the call insn.
        !          1411:      Currently that doesn't matter since explicitly-used regs
        !          1412:      won't be used for reloading.  But if the reloader becomes smarter,
        !          1413:      this will have to change somehow.  */
        !          1414:   for (count = 0; count < nargs; count++)
        !          1415:     if (regvec[count] != 0)
        !          1416:       emit_insn (gen_rtx (USE, VOIDmode, regvec[count]));
        !          1417: 
        !          1418: #ifdef STACK_BOUNDARY
        !          1419:   args_size = (args_size + STACK_BYTES - 1) / STACK_BYTES * STACK_BYTES;
        !          1420: #endif
        !          1421: 
        !          1422:   current_args_size += 1;
        !          1423:   emit_call_1 (fun, get_identifier (XSTR (orgfun, 0)), args_size,
        !          1424:               FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1),
        !          1425:               outmode != VOIDmode ? hard_libcall_value (outmode) : 0,
        !          1426:               old_args_size);
1.1       root     1427: }
                   1428: 
                   1429: /* Expand an assignment that stores the value of FROM into TO.
1.1.1.2 ! root     1430:    If WANT_VALUE is nonzero, return an rtx for the value of TO.
        !          1431:    (This may contain a QUEUED rtx.)
        !          1432:    Otherwise, the returned value is not meaningful.
        !          1433: 
        !          1434:    SUGGEST_REG is no longer actually used.
        !          1435:    It used to mean, copy the value through a register
        !          1436:    and return that register, if that is possible.
        !          1437:    But now we do this if WANT_VALUE.
        !          1438: 
        !          1439:    If the value stored is a constant, we return the constant.  */
1.1       root     1440: 
                   1441: rtx
1.1.1.2 ! root     1442: expand_assignment (to, from, want_value, suggest_reg)
1.1       root     1443:      tree to, from;
1.1.1.2 ! root     1444:      int want_value;
        !          1445:      int suggest_reg;
1.1       root     1446: {
                   1447:   register rtx to_rtx = 0;
                   1448: 
                   1449:   /* Don't crash if the lhs of the assignment was erroneous.  */
                   1450: 
                   1451:   if (TREE_CODE (to) == ERROR_MARK)
                   1452:     return expand_expr (from, 0, VOIDmode, 0);
                   1453: 
                   1454:   /* Assignment of a structure component needs special treatment
1.1.1.2 ! root     1455:      if the structure component's rtx is not simply a MEM.
        !          1456:      Assignment of an array element at a constant index
        !          1457:      has the same problem.  */
        !          1458: 
        !          1459:   if (TREE_CODE (to) == COMPONENT_REF
        !          1460:       || (TREE_CODE (to) == ARRAY_REF
        !          1461:          && TREE_CODE (TREE_OPERAND (to, 1)) == INTEGER_CST
        !          1462:          && TREE_CODE (TYPE_SIZE (TREE_TYPE (to))) == INTEGER_CST))
1.1       root     1463:     {
1.1.1.2 ! root     1464:       register enum machine_mode mode1;
        !          1465:       int bitsize;
1.1       root     1466:       int volstruct = 0;
1.1.1.2 ! root     1467:       tree tem = to;
        !          1468:       int bitpos = 0;
        !          1469:       int unsignedp;
1.1       root     1470: 
1.1.1.2 ! root     1471:       if (TREE_CODE (to) == COMPONENT_REF)
1.1       root     1472:        {
                   1473:          tree field = TREE_OPERAND (to, 1);
1.1.1.2 ! root     1474:          bitsize = TREE_INT_CST_LOW (DECL_SIZE (field)) * DECL_SIZE_UNIT (field);
        !          1475:          mode1 = DECL_MODE (TREE_OPERAND (to, 1));
        !          1476:          unsignedp = TREE_UNSIGNED (field);
1.1       root     1477:        }
1.1.1.2 ! root     1478:       else
1.1       root     1479:        {
1.1.1.2 ! root     1480:          mode1 = TYPE_MODE (TREE_TYPE (to));
        !          1481:          bitsize = GET_MODE_BITSIZE (mode1);
        !          1482:          unsignedp = TREE_UNSIGNED (TREE_TYPE (to));
1.1       root     1483:        }
                   1484: 
1.1.1.2 ! root     1485:       /* Compute cumulative bit-offset for nested component-refs
        !          1486:         and array-refs, and find the ultimate containing object.  */
1.1       root     1487: 
1.1.1.2 ! root     1488:       while (1)
1.1       root     1489:        {
1.1.1.2 ! root     1490:          if (TREE_CODE (tem) == COMPONENT_REF)
        !          1491:            {
        !          1492:              bitpos += DECL_OFFSET (TREE_OPERAND (tem, 1));
        !          1493:              if (TREE_THIS_VOLATILE (tem))
        !          1494:                volstruct = 1;
        !          1495:            }
        !          1496:          else if (TREE_CODE (tem) == ARRAY_REF
        !          1497:                   && TREE_CODE (TREE_OPERAND (tem, 1)) == INTEGER_CST
        !          1498:                   && TREE_CODE (TYPE_SIZE (TREE_TYPE (tem))) == INTEGER_CST)
        !          1499:            {
        !          1500:              bitpos += (TREE_INT_CST_LOW (TREE_OPERAND (tem, 1))
        !          1501:                         * TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (tem)))
        !          1502:                         * TYPE_SIZE_UNIT (TREE_TYPE (tem)));
        !          1503:            }
        !          1504:          else
        !          1505:            break;
        !          1506:          tem = TREE_OPERAND (tem, 0);
1.1       root     1507:        }
                   1508: 
1.1.1.2 ! root     1509:       /* If we are going to use store_bit_field and extract_bit_field,
        !          1510:         make sure to_rtx will be safe for multiple use.  */
        !          1511:       if (mode1 == BImode && want_value)
        !          1512:        tem = stabilize_reference (tem);
1.1       root     1513: 
1.1.1.2 ! root     1514:       to_rtx = expand_expr (tem, 0, VOIDmode, 0);
        !          1515: 
        !          1516:       return store_field (to_rtx, bitsize, bitpos, mode1, from,
        !          1517:                          want_value ? TYPE_MODE (TREE_TYPE (to)) : VOIDmode,
        !          1518:                          unsignedp);
1.1       root     1519:     }
                   1520: 
                   1521:   /* Ordinary treatment.  Expand TO to get a REG or MEM rtx.
                   1522:      Don't re-expand if it was expanded already (in COMPONENT_REF case).  */
                   1523: 
                   1524:   if (to_rtx == 0)
                   1525:     to_rtx = expand_expr (to, 0, VOIDmode, 0);
                   1526: 
                   1527:   /* Compute FROM and store the value in the rtx we got.  */
                   1528: 
1.1.1.2 ! root     1529:   return store_expr (from, to_rtx, want_value);
1.1       root     1530: }
                   1531: 
                   1532: /* Generate code for computing expression EXP,
1.1.1.2 ! root     1533:    and storing the value into TARGET.
        !          1534:    Returns TARGET or an equivalent value.
        !          1535:    TARGET may contain a QUEUED rtx.
1.1       root     1536: 
1.1.1.2 ! root     1537:    If SUGGEST_REG is nonzero, copy the value through a register
        !          1538:    and return that register, if that is possible.
        !          1539: 
        !          1540:    If the value stored is a constant, we return the constant.  */
        !          1541: 
        !          1542: rtx
        !          1543: store_expr (exp, target, suggest_reg)
1.1       root     1544:      register tree exp;
                   1545:      register rtx target;
1.1.1.2 ! root     1546:      int suggest_reg;
1.1       root     1547: {
1.1.1.2 ! root     1548:   register rtx temp;
        !          1549:   int dont_return_target = 0;
        !          1550: 
        !          1551:   /* Copying a non-constant CONSTRUCTOR needs special treatment.  */
        !          1552: 
        !          1553:   if (TREE_CODE (exp) == CONSTRUCTOR && ! TREE_LITERAL (exp))
        !          1554:     {
        !          1555:       store_constructor (exp, target);
        !          1556:       return target;
        !          1557:     }
        !          1558: 
        !          1559:   if (suggest_reg && GET_CODE (target) == MEM && GET_MODE (target) != BLKmode)
        !          1560:     /* If target is in memory and caller wants value in a register instead,
        !          1561:        arrange that.  Pass TARGET as target for expand_expr so that,
        !          1562:        if EXP is another assignment, SUGGEST_REG will be nonzero for it.
        !          1563:        We know expand_expr will not use the target in that case.  */
        !          1564:     {
        !          1565:       temp = expand_expr (exp, cse_not_expected ? 0 : target,
        !          1566:                          GET_MODE (target), 0);
        !          1567:       if (GET_MODE (temp) != BLKmode && GET_MODE (temp) != VOIDmode)
        !          1568:        temp = copy_to_reg (temp);
        !          1569:       dont_return_target = 1;
        !          1570:     }
        !          1571:   else if (queued_subexp_p (target))
        !          1572:     /* If target contains a postincrement, it is not safe
        !          1573:        to use as the returned value.  It would access the wrong
        !          1574:        place by the time the queued increment gets output.
        !          1575:        So copy the value through a temporary and use that temp
        !          1576:        as the result.  */
        !          1577:     {
        !          1578:       temp = expand_expr (exp, 0, GET_MODE (target), 0);
        !          1579:       if (GET_MODE (temp) != BLKmode && GET_MODE (temp) != VOIDmode)
        !          1580:        temp = copy_to_reg (temp);
        !          1581:       dont_return_target = 1;
        !          1582:     }
        !          1583:   else
        !          1584:     {
        !          1585:       temp = expand_expr (exp, target, GET_MODE (target), 0);
        !          1586:       /* DO return TARGET if it's a specified hardware register.
        !          1587:         expand_return relies on this.  */
        !          1588:       if (!(target && GET_CODE (target) == REG
        !          1589:            && REGNO (target) < FIRST_PSEUDO_REGISTER)
        !          1590:          && (CONSTANT_P (temp) || GET_CODE (temp) == CONST_DOUBLE))
        !          1591:        dont_return_target = 1;
        !          1592:     }
        !          1593: 
        !          1594:   /* If value was not generated in the target, store it there.  */
        !          1595: 
1.1       root     1596:   if (temp != target && TREE_CODE (exp) != ERROR_MARK)
                   1597:     {
                   1598:       target = protect_from_queue (target, 1);
                   1599:       if (GET_MODE (temp) != GET_MODE (target)
                   1600:          && GET_MODE (temp) != VOIDmode)
1.1.1.2 ! root     1601:        {
        !          1602:          int unsignedp = TREE_UNSIGNED (TREE_TYPE (exp));
        !          1603:          if (dont_return_target)
        !          1604:            temp = convert_to_mode (GET_MODE (target), temp, unsignedp);
        !          1605:          else
        !          1606:            convert_move (target, temp, unsignedp);
        !          1607:        }
        !          1608: 
1.1       root     1609:       else if (GET_MODE (temp) == BLKmode)
                   1610:        emit_block_move (target, temp, expr_size (exp),
                   1611:                         TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
                   1612:       else
                   1613:        emit_move_insn (target, temp);
                   1614:     }
1.1.1.2 ! root     1615:   if (dont_return_target)
        !          1616:     return temp;
1.1       root     1617:   return target;
                   1618: }
                   1619: 
1.1.1.2 ! root     1620: /* Store the value of constructor EXP into the rtx TARGET.
        !          1621:    TARGET is either a REG or a MEM.  */
1.1       root     1622: 
1.1.1.2 ! root     1623: static void
        !          1624: store_constructor (exp, target)
        !          1625:      tree exp;
        !          1626:      rtx target;
1.1       root     1627: {
1.1.1.2 ! root     1628:   if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
1.1       root     1629:     {
1.1.1.2 ! root     1630:       register tree elt;
1.1       root     1631: 
1.1.1.2 ! root     1632:       /* If the constructor has fewer fields than the structure,
        !          1633:         clear the whole structure first.  */
1.1       root     1634: 
1.1.1.2 ! root     1635:       if (list_length (CONSTRUCTOR_ELTS (exp))
        !          1636:          != list_length (TYPE_FIELDS (TREE_TYPE (exp))))
        !          1637:        clear_storage (target, int_size_in_bytes (TREE_TYPE (exp)));
        !          1638:       else
        !          1639:        /* Inform later passes that the old value is dead.  */
        !          1640:        emit_insn (gen_rtx (CLOBBER, VOIDmode, target));
        !          1641: 
        !          1642:       /* Store each element of the constructor into
        !          1643:         the corresponding field of TARGET.  */
        !          1644: 
        !          1645:       for (elt = CONSTRUCTOR_ELTS (exp); elt; elt = TREE_CHAIN (elt))
        !          1646:        {
        !          1647:          register tree field = TREE_PURPOSE (elt);
        !          1648:          register enum machine_mode mode;
        !          1649:          int bitsize;
        !          1650:          int bitpos;
        !          1651:          int unsignedp;
        !          1652: 
        !          1653:          bitsize = TREE_INT_CST_LOW (DECL_SIZE (field)) * DECL_SIZE_UNIT (field);
        !          1654:          mode = DECL_MODE (field);
        !          1655:          unsignedp = TREE_UNSIGNED (field);
        !          1656: 
        !          1657:          bitpos = DECL_OFFSET (field);
        !          1658: 
        !          1659:          store_field (target, bitsize, bitpos, mode, TREE_VALUE (elt),
        !          1660:                       VOIDmode, 0);
        !          1661:        }
        !          1662:     }
        !          1663:   else if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
        !          1664:     {
        !          1665:       register tree elt;
        !          1666:       register int i;
        !          1667:       tree domain = TYPE_DOMAIN (TREE_TYPE (exp));
        !          1668:       int minelt = TREE_INT_CST_LOW (TYPE_MIN_VALUE (domain));
        !          1669:       int maxelt = TREE_INT_CST_LOW (TYPE_MAX_VALUE (domain));
        !          1670:       tree elttype = TREE_TYPE (TREE_TYPE (exp));
        !          1671: 
        !          1672:       /* If the constructor has fewer fields than the structure,
        !          1673:         clear the whole structure first.  */
        !          1674: 
        !          1675:       if (list_length (CONSTRUCTOR_ELTS (exp)) < maxelt - minelt + 1)
        !          1676:        clear_storage (target, maxelt - minelt + 1);
        !          1677:       else
        !          1678:        /* Inform later passes that the old value is dead.  */
        !          1679:        emit_insn (gen_rtx (CLOBBER, VOIDmode, target));
        !          1680: 
        !          1681:       /* Store each element of the constructor into
        !          1682:         the corresponding element of TARGET, determined
        !          1683:         by counting the elements.  */
        !          1684:       for (elt = CONSTRUCTOR_ELTS (exp), i = 0;
        !          1685:           elt;
        !          1686:           elt = TREE_CHAIN (elt), i++)
        !          1687:        {
        !          1688:          register enum machine_mode mode;
        !          1689:          int bitsize;
        !          1690:          int bitpos;
        !          1691:          int unsignedp;
        !          1692: 
        !          1693:          mode = TYPE_MODE (elttype);
        !          1694:          bitsize = GET_MODE_BITSIZE (mode);
        !          1695:          unsignedp = TREE_UNSIGNED (elttype);
        !          1696: 
        !          1697:          bitpos = (i * TREE_INT_CST_LOW (TYPE_SIZE (elttype))
        !          1698:                    * TYPE_SIZE_UNIT (elttype));
        !          1699: 
        !          1700:          store_field (target, bitsize, bitpos, mode, TREE_VALUE (elt),
        !          1701:                       VOIDmode, 0);
        !          1702:        }
        !          1703:     }
        !          1704: }
        !          1705: 
        !          1706: /* Store the value of EXP (an expression tree)
        !          1707:    into a subfield of TARGET which has mode MODE and occupies
        !          1708:    BITSIZE bits, starting BITPOS bits from the start of TARGET.
        !          1709: 
        !          1710:    If VALUE_MODE is VOIDmode, return nothing in particular.
        !          1711:    UNSIGNEDP is not used in this case.
        !          1712: 
        !          1713:    Otherwise, return an rtx for the value stored.  This rtx
        !          1714:    has mode VALUE_MODE if that is convenient to do.
        !          1715:    In this case, UNSIGNEDP must be nonzero if the value is an unsigned type.  */
        !          1716: 
        !          1717: static rtx
        !          1718: store_field (target, bitsize, bitpos, mode, exp, value_mode, unsignedp)
        !          1719:      rtx target;
        !          1720:      int bitsize, bitpos;
        !          1721:      enum machine_mode mode;
        !          1722:      tree exp;
        !          1723:      enum machine_mode value_mode;
        !          1724:      int unsignedp;
        !          1725: {
        !          1726:   /* If the structure is in a register or if the component
        !          1727:      is a bit field, we cannot use addressing to access it.
        !          1728:      Use bit-field techniques or SUBREG to store in it.  */
        !          1729: 
        !          1730:   if (mode == BImode || GET_CODE (target) == REG
        !          1731:       || GET_CODE (target) == SUBREG)
        !          1732:     {
        !          1733:       store_bit_field (target, bitsize, bitpos,
        !          1734:                       mode,
        !          1735:                       expand_expr (exp, 0, VOIDmode, 0));
        !          1736:       if (value_mode != VOIDmode)
        !          1737:        return extract_bit_field (target, bitsize, bitpos, unsignedp,
        !          1738:                                  0, value_mode, 0);
        !          1739:       return const0_rtx;
        !          1740:     }
        !          1741:   else
        !          1742:     {
        !          1743:       rtx addr = XEXP (target, 0);
        !          1744:       rtx to_rtx;
        !          1745: 
        !          1746:       /* If a value is wanted, it must be the lhs;
        !          1747:         so make the address stable for multiple use.  */
        !          1748: 
        !          1749:       if (value_mode != VOIDmode && GET_CODE (addr) != REG
        !          1750:          && ! CONSTANT_ADDRESS_P (addr))
        !          1751:        addr = copy_to_reg (addr);
        !          1752: 
        !          1753:       /* Now build a reference to just the desired component.  */
        !          1754: 
        !          1755:       to_rtx = change_address (target, mode,
        !          1756:                               plus_constant (addr,
        !          1757:                                              (bitpos / BITS_PER_UNIT)));
        !          1758:       to_rtx->in_struct = 1;
        !          1759: 
        !          1760:       return store_expr (exp, to_rtx, value_mode != VOIDmode);
        !          1761:     }
        !          1762: }
        !          1763: 
        !          1764: /* Given an rtx VALUE that may contain additions and multiplications,
        !          1765:    return an equivalent value that just refers to a register or memory.
        !          1766:    This is done by generating instructions to perform the arithmetic
        !          1767:    and returning a pseudo-register containing the value.  */
        !          1768: 
        !          1769: rtx
        !          1770: force_operand (value, target)
        !          1771:      rtx value, target;
        !          1772: {
        !          1773:   register optab binoptab = 0;
        !          1774:   register rtx op2;
        !          1775:   /* Use subtarget as the target for operand 0 of a binary operation.  */
        !          1776:   register rtx subtarget = (target != 0 && GET_CODE (target) == REG ? target : 0);
        !          1777: 
        !          1778:   if (GET_CODE (value) == PLUS)
        !          1779:     binoptab = add_optab;
        !          1780:   else if (GET_CODE (value) == MINUS)
        !          1781:     binoptab = sub_optab;
        !          1782:   else if (GET_CODE (value) == MULT)
        !          1783:     {
        !          1784:       op2 = XEXP (value, 1);
        !          1785:       if (!CONSTANT_P (op2)
        !          1786:          && !(GET_CODE (op2) == REG && op2 != subtarget))
        !          1787:        subtarget = 0;
        !          1788:       return expand_mult (GET_MODE (value),
        !          1789:                          force_operand (XEXP (value, 0), subtarget),
        !          1790:                          force_operand (op2, 0),
        !          1791:                          target, 0);
        !          1792:     }
        !          1793: 
        !          1794:   if (binoptab)
        !          1795:     {
        !          1796:       op2 = XEXP (value, 1);
        !          1797:       if (!CONSTANT_P (op2)
        !          1798:          && !(GET_CODE (op2) == REG && op2 != subtarget))
        !          1799:        subtarget = 0;
        !          1800:       if (binoptab == sub_optab
        !          1801:          && GET_CODE (op2) == CONST_INT && INTVAL (op2) < 0)
        !          1802:        {
        !          1803:          binoptab = add_optab;
        !          1804:          op2 = gen_rtx (CONST_INT, VOIDmode, - INTVAL (op2));
        !          1805:        }
        !          1806:       return expand_binop (GET_MODE (value), binoptab,
        !          1807:                           force_operand (XEXP (value, 0), subtarget),
        !          1808:                           force_operand (op2, 0),
        !          1809:                           target, 0, OPTAB_LIB_WIDEN);
        !          1810:       /* We give UNSIGNEP = 0 to expand_binop
        !          1811:         because the only operations we are expanding here are signed ones.  */
        !          1812:     }
        !          1813:   return value;
        !          1814: }
        !          1815: 
        !          1816: /* expand_expr: generate code for computing expression EXP.
        !          1817:    An rtx for the computed value is returned.
        !          1818: 
        !          1819:    The value may be stored in TARGET if TARGET is nonzero.
1.1       root     1820:    TARGET is just a suggestion; callers must assume that
                   1821:    the rtx returned may not be the same as TARGET.
                   1822: 
1.1.1.2 ! root     1823:    If TARGET is CONST0_RTX, it means that the value will be ignored.
        !          1824: 
1.1       root     1825:    If TMODE is not VOIDmode, it suggests generating the
                   1826:    result in mode TMODE.  But this is done only when convenient.
                   1827:    Otherwise, TMODE is ignored and the value generated in its natural mode.
                   1828:    TMODE is just a suggestion; callers must assume that
                   1829:    the rtx returned may not have mode TMODE.
                   1830: 
1.1.1.2 ! root     1831:    If MODIFIER is EXPAND_SUM then when EXP is an addition
1.1       root     1832:    we can return an rtx of the form (MULT (REG ...) (CONST_INT ...))
                   1833:    or a nest of (PLUS ...) and (MINUS ...) where the terms are
                   1834:    products as above, or REG or MEM, or constant.
1.1.1.2 ! root     1835:    Ordinarily in such cases we would output mul or add instructions
        !          1836:    and then return a pseudo reg containing the sum.
        !          1837: 
        !          1838:    If MODIFIER is EXPAND_CONST_ADDRESS then it is ok to return
        !          1839:    a MEM rtx whose address is a constant that isn't a legitimate address.  */
1.1       root     1840: 
                   1841: /* Subroutine of expand_expr:
                   1842:    return the target to use when recursively expanding
                   1843:    the first operand of an arithmetic operation.  */
                   1844: 
                   1845: static rtx
                   1846: validate_subtarget (subtarget, otherop)
                   1847:      rtx subtarget;
                   1848:      tree otherop;
                   1849: {
                   1850:   if (TREE_LITERAL (otherop))
                   1851:     return subtarget;
                   1852:   if (TREE_CODE (otherop) == VAR_DECL
                   1853:       && DECL_RTL (otherop) != subtarget)
                   1854:     return subtarget;
                   1855:   return 0;
                   1856: }
                   1857: 
                   1858: rtx
1.1.1.2 ! root     1859: expand_expr (exp, target, tmode, modifier)
1.1       root     1860:      register tree exp;
                   1861:      rtx target;
                   1862:      enum machine_mode tmode;
1.1.1.2 ! root     1863:      enum expand_modifier modifier;
1.1       root     1864: {
                   1865:   register rtx op0, op1, temp;
                   1866:   tree type = TREE_TYPE (exp);
                   1867:   register enum machine_mode mode = TYPE_MODE (type);
                   1868:   register enum tree_code code = TREE_CODE (exp);
1.1.1.2 ! root     1869:   optab this_optab;
1.1       root     1870:   int negate_1;
                   1871:   /* Use subtarget as the target for operand 0 of a binary operation.  */
                   1872:   rtx subtarget = (target != 0 && GET_CODE (target) == REG ? target : 0);
1.1.1.2 ! root     1873:   rtx original_target = target;
        !          1874:   int ignore = target == const0_rtx;
        !          1875: 
        !          1876:   if (ignore) target = 0, original_target = 0;
1.1       root     1877: 
                   1878:   /* If will do cse, generate all results into registers
                   1879:      since 1) that allows cse to find more things
                   1880:      and 2) otherwise cse could produce an insn the machine
                   1881:      cannot support.  */
                   1882: 
                   1883:   if (! cse_not_expected && mode != BLKmode)
                   1884:     target = subtarget;
                   1885: 
1.1.1.2 ! root     1886:   /* No sense saving up arithmetic to be done
        !          1887:      if it's all in the wrong mode to form part of an address.
        !          1888:      And force_operand won't know whether to sign-extend or zero-extend.  */
        !          1889: 
        !          1890:   if (mode != Pmode && modifier == EXPAND_SUM)
        !          1891:     modifier = (enum expand_modifier) 0;
        !          1892: 
1.1       root     1893:   switch (code)
                   1894:     {
                   1895:     case FUNCTION_DECL:
                   1896:     case VAR_DECL:
                   1897:     case PARM_DECL:
                   1898:     case RESULT_DECL:
                   1899:       if (DECL_RTL (exp) == 0)
                   1900:        abort ();
                   1901:       if (GET_CODE (DECL_RTL (exp)) == SYMBOL_REF)
                   1902:        abort ();
1.1.1.2 ! root     1903:       if (GET_CODE (DECL_RTL (exp)) == MEM
        !          1904:          && modifier != EXPAND_CONST_ADDRESS)
        !          1905:        {
        !          1906:          /* DECL_RTL probably contains a constant address.
        !          1907:             On RISC machines where a constant address isn't valid,
        !          1908:             make some insns to get that address into a register.  */
        !          1909:          if (!memory_address_p (DECL_MODE (exp), XEXP (DECL_RTL (exp), 0)))
        !          1910:            return change_address (DECL_RTL (exp), VOIDmode,
        !          1911:                                   copy_rtx (XEXP (DECL_RTL (exp), 0)));
        !          1912:        }
1.1       root     1913:       return DECL_RTL (exp);
                   1914: 
                   1915:     case INTEGER_CST:
                   1916:       return gen_rtx (CONST_INT, VOIDmode, TREE_INT_CST_LOW (exp));
                   1917: 
                   1918:     case CONST_DECL:
                   1919:       return expand_expr (DECL_INITIAL (exp), target, VOIDmode, 0);
                   1920: 
                   1921:     case REAL_CST:
                   1922:       if (TREE_CST_RTL (exp))
                   1923:        return TREE_CST_RTL (exp);
                   1924:       /* If optimized, generate immediate float
                   1925:         which will be turned into memory float if necessary.  */
                   1926:       if (!cse_not_expected)
                   1927:        return immed_real_const (exp);
                   1928:       output_constant_def (exp);
                   1929:       return TREE_CST_RTL (exp);
                   1930: 
                   1931:     case COMPLEX_CST:
                   1932:     case STRING_CST:
                   1933:       if (TREE_CST_RTL (exp))
                   1934:        return TREE_CST_RTL (exp);
                   1935:       output_constant_def (exp);
                   1936:       return TREE_CST_RTL (exp);
                   1937: 
                   1938:     case SAVE_EXPR:
                   1939:       if (SAVE_EXPR_RTL (exp) == 0)
                   1940:        {
                   1941:          SAVE_EXPR_RTL (exp) = gen_reg_rtx (mode);
1.1.1.2 ! root     1942:          store_expr (TREE_OPERAND (exp, 0), SAVE_EXPR_RTL (exp), 0);
1.1       root     1943:        }
1.1.1.2 ! root     1944:       /* Don't let the same rtl node appear in two places.  */
1.1       root     1945:       return SAVE_EXPR_RTL (exp);
                   1946: 
1.1.1.2 ! root     1947:     case RTL_EXPR:
        !          1948:       emit_insn (RTL_EXPR_SEQUENCE (exp));
        !          1949:       return RTL_EXPR_RTL (exp);
        !          1950: 
        !          1951:     case CONSTRUCTOR:
        !          1952:       /* All elts simple constants => refer to a constant in memory.  */
        !          1953:       if (TREE_STATIC (exp))
        !          1954:        /* For aggregate types with non-BLKmode modes,
        !          1955:           this should ideally construct a CONST_INT.  */
        !          1956:        return output_constant_def (exp);
        !          1957: 
        !          1958:       if (ignore)
        !          1959:        {
        !          1960:          tree elt;
        !          1961:          for (elt = CONSTRUCTOR_ELTS (exp); elt; elt = TREE_CHAIN (elt))
        !          1962:            expand_expr (TREE_VALUE (elt), const0_rtx, VOIDmode, 0);
        !          1963:          return const0_rtx;
        !          1964:        }
        !          1965:       else
        !          1966:        {
        !          1967:          if (target == 0)
        !          1968:            target = gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)),
        !          1969:                              get_structure_value_addr (expr_size (exp)));
        !          1970:          store_expr (exp, target, 0);
        !          1971:          return target;
        !          1972:        }
        !          1973: 
1.1       root     1974:     case INDIRECT_REF:
                   1975:       {
                   1976:        tree exp1 = TREE_OPERAND (exp, 0);
                   1977:        tree exp2;
                   1978: 
                   1979:        /* A SAVE_EXPR as the address in an INDIRECT_EXPR is generated
                   1980:           for  *PTR += ANYTHING  where PTR is put inside the SAVE_EXPR.
                   1981:           This code has the same general effect as simply doing
                   1982:           expand_expr on the save expr, except that the expression PTR
                   1983:           is computed for use as a memory address.  This means different
                   1984:           code, suitable for indexing, may be generated.  */
                   1985:        if (TREE_CODE (exp1) == SAVE_EXPR
                   1986:            && SAVE_EXPR_RTL (exp1) == 0
                   1987:            && TREE_CODE (exp2 = TREE_OPERAND (exp1, 0)) != ERROR_MARK
                   1988:            && TYPE_MODE (TREE_TYPE (exp1)) == Pmode
                   1989:            && TYPE_MODE (TREE_TYPE (exp2)) == Pmode)
                   1990:          {
1.1.1.2 ! root     1991:            temp = expand_expr (TREE_OPERAND (exp1, 0), 0, VOIDmode, EXPAND_SUM);
1.1       root     1992:            op0 = memory_address (mode, temp);
                   1993:            op0 = copy_all_regs (op0);
                   1994:            SAVE_EXPR_RTL (exp1) = op0;
                   1995:          }
                   1996:        else
                   1997:          {
1.1.1.2 ! root     1998:            op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, EXPAND_SUM);
1.1       root     1999:            op0 = memory_address (mode, op0);
                   2000:          }
                   2001:       }
                   2002:       temp = gen_rtx (MEM, mode, op0);
1.1.1.2 ! root     2003:       /* If address was computed by addition,
        !          2004:         mark this as an element of an aggregate.  */
        !          2005:       if (TREE_CODE (TREE_OPERAND (exp, 0)) == PLUS_EXPR
        !          2006:          || (TREE_CODE (TREE_OPERAND (exp, 0)) == SAVE_EXPR
        !          2007:              && TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) == PLUS_EXPR))
        !          2008:        temp->in_struct = 1;
        !          2009:       temp->volatil = TREE_THIS_VOLATILE (exp) | flag_volatile;
        !          2010:       temp->unchanging = TREE_READONLY (exp);
        !          2011:       return temp;
        !          2012: 
        !          2013:     case ARRAY_REF:
        !          2014:       if (TREE_CODE (TREE_OPERAND (exp, 1)) != INTEGER_CST
        !          2015:          || TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) != INTEGER_CST)
        !          2016:        {
        !          2017:          /* Nonconstant array index or nonconstant element size.
        !          2018:             Generate the tree for *(&array+index) and expand that,
        !          2019:             except do it in a language-independent way
        !          2020:             and don't complain about non-lvalue arrays.
        !          2021:             `mark_addressable' should already have been called
        !          2022:             for any array for which this case will be reached.  */
        !          2023: 
        !          2024:          tree array_adr = build (ADDR_EXPR, TYPE_POINTER_TO (type),
        !          2025:                                  TREE_OPERAND (exp, 0));
        !          2026:          tree index = TREE_OPERAND (exp, 1);
        !          2027:          tree elt;
        !          2028: 
        !          2029:          /* Convert the integer argument to a type the same size as a pointer
        !          2030:             so the multiply won't overflow spuriously.  */
        !          2031:          if (TYPE_PRECISION (TREE_TYPE (index)) != POINTER_SIZE)
        !          2032:            index = convert (type_for_size (POINTER_SIZE, 0), index);
        !          2033: 
        !          2034:          /* The array address isn't volatile even if the array is.  */
        !          2035:          TREE_VOLATILE (array_adr) = 0;
        !          2036: 
        !          2037:          elt = build (INDIRECT_REF, type,
        !          2038:                       fold (build (PLUS_EXPR, TYPE_POINTER_TO (type),
        !          2039:                                    array_adr,
        !          2040:                                    fold (build (MULT_EXPR,
        !          2041:                                                 TYPE_POINTER_TO (type),
        !          2042:                                                 index, size_in_bytes (type))))));
        !          2043: 
        !          2044:          return expand_expr (elt, target, tmode, modifier);
        !          2045:        }
        !          2046:       /* Treat array-ref with constant index as a component-ref.  */
1.1       root     2047: 
                   2048:     case COMPONENT_REF:
                   2049:       {
1.1.1.2 ! root     2050:        register enum machine_mode mode1;
1.1       root     2051:        int volstruct = 0;
                   2052:        tree dbg1 = TREE_OPERAND (exp, 0);  /* For debugging */
1.1.1.2 ! root     2053:        int bitsize;
        !          2054:        tree tem = exp;
        !          2055:        int bitpos = 0;
        !          2056:        int unsignedp;
1.1       root     2057: 
1.1.1.2 ! root     2058:        if (TREE_CODE (exp) == COMPONENT_REF)
1.1       root     2059:          {
                   2060:            tree field = TREE_OPERAND (exp, 1);
1.1.1.2 ! root     2061:            bitsize = TREE_INT_CST_LOW (DECL_SIZE (field)) * DECL_SIZE_UNIT (field);
        !          2062:            mode1 = DECL_MODE (TREE_OPERAND (exp, 1));
        !          2063:            unsignedp = TREE_UNSIGNED (field);
1.1       root     2064:          }
1.1.1.2 ! root     2065:        else
1.1       root     2066:          {
1.1.1.2 ! root     2067:            mode1 = TYPE_MODE (TREE_TYPE (exp));
        !          2068:            bitsize = GET_MODE_BITSIZE (mode1);
        !          2069:            unsignedp = TREE_UNSIGNED (TREE_TYPE (exp));
1.1       root     2070:          }
                   2071: 
1.1.1.2 ! root     2072:        /* Compute cumulative bit-offset for nested component-refs
        !          2073:           and array-refs, and find the ultimate containing object.  */
        !          2074: 
        !          2075:        while (1)
1.1       root     2076:          {
1.1.1.2 ! root     2077:            if (TREE_CODE (tem) == COMPONENT_REF)
        !          2078:              {
        !          2079:                bitpos += DECL_OFFSET (TREE_OPERAND (tem, 1));
        !          2080:                if (TREE_THIS_VOLATILE (tem))
        !          2081:                  volstruct = 1;
        !          2082:              }
        !          2083:            else if (TREE_CODE (tem) == ARRAY_REF
        !          2084:                     && TREE_CODE (TREE_OPERAND (tem, 1)) == INTEGER_CST
        !          2085:                     && TREE_CODE (TYPE_SIZE (TREE_TYPE (tem))) == INTEGER_CST)
        !          2086:              {
        !          2087:                bitpos += (TREE_INT_CST_LOW (TREE_OPERAND (tem, 1))
        !          2088:                           * TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (tem)))
        !          2089:                           * TYPE_SIZE_UNIT (TREE_TYPE (tem)));
        !          2090:              }
        !          2091:            else
        !          2092:              break;
        !          2093:            tem = TREE_OPERAND (tem, 0);
1.1       root     2094:          }
                   2095: 
1.1.1.2 ! root     2096:        op0 = expand_expr (tem, 0, VOIDmode,
        !          2097:                           (modifier == EXPAND_CONST_ADDRESS
        !          2098:                            ? modifier : EXPAND_NORMAL));
1.1       root     2099: 
1.1.1.2 ! root     2100:        if (mode1 == BImode || GET_CODE (op0) == REG
        !          2101:            || GET_CODE (op0) == SUBREG)
        !          2102:          {
        !          2103:            return extract_bit_field (op0, bitsize, bitpos, unsignedp,
        !          2104:                                      target, mode, tmode);
        !          2105:          }
        !          2106:        /* Get a reference to just this component.  */
        !          2107:        if (modifier == EXPAND_CONST_ADDRESS)
        !          2108:          op0 = gen_rtx (MEM, mode1, plus_constant (XEXP (op0, 0),
        !          2109:                                                    (bitpos / BITS_PER_UNIT)));
        !          2110:        else
        !          2111:          op0 = change_address (op0, mode1,
        !          2112:                                plus_constant (XEXP (op0, 0),
        !          2113:                                               (bitpos / BITS_PER_UNIT)));
        !          2114:        op0->in_struct = 1;
        !          2115:        op0->volatil = volstruct;
        !          2116:        /* If OP0 is in the shared structure-value stack slot,
        !          2117:           and it is not BLKmode, copy it into a register.
        !          2118:           The shared slot may be clobbered at any time by another call.
        !          2119:           BLKmode is safe because our caller will either copy the value away
        !          2120:           or take another component and come back here.  */
        !          2121:        if (mode != BLKmode
        !          2122:            && TREE_CODE (TREE_OPERAND (exp, 0)) == CALL_EXPR
        !          2123:            && TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == BLKmode)
        !          2124:          op0 = copy_to_reg (op0);
        !          2125:        if (mode == mode1 || mode1 == BLKmode || mode1 == tmode)
        !          2126:          return op0;
        !          2127:        if (target == 0)
        !          2128:          target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
        !          2129:        convert_move (target, op0, unsignedp);
        !          2130:        return target;
1.1       root     2131:       }
                   2132: 
                   2133:       /* Intended for a reference to a buffer of a file-object in Pascal.
                   2134:         But it's not certain that a special tree code will really be
                   2135:         necessary for these.  INDIRECT_REF might work for them.  */
                   2136:     case BUFFER_REF:
                   2137:       abort ();
                   2138: 
                   2139:     case CALL_EXPR:
1.1.1.2 ! root     2140:       /* Check for a built-in function.  */
        !          2141:       if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
        !          2142:          && TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) == FUNCTION_DECL
        !          2143:          && DECL_FUNCTION_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
        !          2144:        return expand_builtin (exp, target, subtarget, tmode);
1.1       root     2145:       /* If this call was expanded already by preexpand_calls,
                   2146:         just return the result we got.  */
                   2147:       if (CALL_EXPR_RTL (exp) != 0)
                   2148:        return CALL_EXPR_RTL (exp);
1.1.1.2 ! root     2149:       return expand_call (exp, target, ignore);
1.1       root     2150: 
                   2151:     case NOP_EXPR:
                   2152:     case CONVERT_EXPR:
1.1.1.2 ! root     2153:       if (TREE_CODE (type) == VOID_TYPE || ignore)
1.1       root     2154:        {
1.1.1.2 ! root     2155:          expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, modifier);
1.1       root     2156:          return const0_rtx;
                   2157:        }
                   2158:       if (mode == TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
1.1.1.2 ! root     2159:        return expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, modifier);
1.1       root     2160:       op0 = expand_expr (TREE_OPERAND (exp, 0), 0, mode, 0);
1.1.1.2 ! root     2161:       if (GET_MODE (op0) == mode || GET_MODE (op0) == VOIDmode)
1.1       root     2162:        return op0;
1.1.1.2 ! root     2163:       if (flag_force_mem && GET_CODE (op0) == MEM)
        !          2164:        op0 = copy_to_reg (op0);
1.1       root     2165:       if (target == 0)
                   2166:        target = gen_reg_rtx (mode);
1.1.1.2 ! root     2167:       convert_move (target, op0, TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
1.1       root     2168:       return target;
                   2169: 
                   2170:     case PLUS_EXPR:
                   2171:       preexpand_calls (exp);
1.1.1.2 ! root     2172:       if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST
        !          2173:          && modifier == EXPAND_SUM)
1.1       root     2174:        {
1.1.1.2 ! root     2175:          op1 = expand_expr (TREE_OPERAND (exp, 1), subtarget, VOIDmode, EXPAND_SUM);
1.1       root     2176:          op1 = plus_constant (op1, TREE_INT_CST_LOW (TREE_OPERAND (exp, 0)));
1.1.1.2 ! root     2177:          return op1;
1.1       root     2178:        }
                   2179:       negate_1 = 1;
                   2180:     plus_minus:
1.1.1.2 ! root     2181:       if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
        !          2182:          && modifier == EXPAND_SUM)
1.1       root     2183:        {
1.1.1.2 ! root     2184:          op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, EXPAND_SUM);
1.1       root     2185:          op0 = plus_constant (op0,
                   2186:                               negate_1 * TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)));
1.1.1.2 ! root     2187:          return op0;
1.1       root     2188:        }
                   2189:       this_optab = add_optab;
1.1.1.2 ! root     2190:       if (modifier != EXPAND_SUM) goto binop;
1.1       root     2191:       subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1));
1.1.1.2 ! root     2192:       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, EXPAND_SUM);
        !          2193:       op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, EXPAND_SUM);
1.1       root     2194:       /* Put a sum last, to simplify what follows.  */
                   2195: #ifdef OLD_INDEXING
                   2196:       if (GET_CODE (op1) == MULT)
                   2197:        {
                   2198:          temp = op0;
                   2199:          op0 = op1;
                   2200:          op1 = temp;
                   2201:        }
                   2202: #endif
                   2203: #ifndef OLD_INDEXING
                   2204:       /* Make sure any term that's a sum with a constant comes last.  */
                   2205:       if (GET_CODE (op0) == PLUS
1.1.1.2 ! root     2206:          && CONSTANT_P (XEXP (op0, 1)))
1.1       root     2207:        {
                   2208:          temp = op0;
                   2209:          op0 = op1;
                   2210:          op1 = temp;
                   2211:        }
                   2212:       /* If adding to a sum including a constant,
                   2213:         associate it to put the constant outside.  */
                   2214:       if (GET_CODE (op1) == PLUS
1.1.1.2 ! root     2215:          && CONSTANT_P (XEXP (op1, 1)))
1.1       root     2216:        {
                   2217:          op0 = gen_rtx (PLUS, mode, XEXP (op1, 0), op0);
                   2218:          if (GET_CODE (XEXP (op1, 1)) == CONST_INT)
                   2219:            return plus_constant (op0, INTVAL (XEXP (op1, 1)));
                   2220:          else
                   2221:            return gen_rtx (PLUS, mode, op0, XEXP (op1, 1));
                   2222:        }
                   2223: #endif
                   2224:       return gen_rtx (PLUS, mode, op0, op1);
                   2225: 
                   2226:     case MINUS_EXPR:
                   2227:       preexpand_calls (exp);
                   2228:       if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
                   2229:        {
1.1.1.2 ! root     2230:          if (modifier == EXPAND_SUM)
        !          2231:            {
        !          2232:              negate_1 = -1;
        !          2233:              goto plus_minus;
        !          2234:            }
        !          2235:          subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1));
        !          2236:          op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
        !          2237:          op1 = gen_rtx (CONST_INT, VOIDmode,
        !          2238:                         - TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)));
        !          2239:          this_optab = add_optab;
        !          2240:          goto binop2;
1.1       root     2241:        }
                   2242:       this_optab = sub_optab;
                   2243:       goto binop;
                   2244: 
                   2245:     case MULT_EXPR:
                   2246:       preexpand_calls (exp);
                   2247:       /* If first operand is constant, swap them.
                   2248:         Thus the following special case checks need only
                   2249:         check the second operand.  */
                   2250:       if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST)
                   2251:        {
                   2252:          register tree t1 = TREE_OPERAND (exp, 0);
                   2253:          TREE_OPERAND (exp, 0) = TREE_OPERAND (exp, 1);
                   2254:          TREE_OPERAND (exp, 1) = t1;
                   2255:        }
                   2256: 
                   2257:       /* Attempt to return something suitable for generating an
                   2258:         indexed address, for machines that support that.  */
                   2259: 
1.1.1.2 ! root     2260:       if (modifier == EXPAND_SUM
        !          2261:          && TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST) 
1.1       root     2262:        {
1.1.1.2 ! root     2263:          op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, EXPAND_SUM);
        !          2264: 
        !          2265:          /* Apply distributive law if OP0 is x+c.  */
        !          2266:          if (GET_CODE (op0) == PLUS
        !          2267:              && GET_CODE (XEXP (op0, 1)) == CONST_INT)
        !          2268:            return gen_rtx (PLUS, mode,
        !          2269:                            gen_rtx (MULT, mode, XEXP (op0, 0),
        !          2270:                                     gen_rtx (CONST_INT, VOIDmode,
        !          2271:                                              TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)))),
        !          2272:                            gen_rtx (CONST_INT, VOIDmode,
        !          2273:                                     (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1))
        !          2274:                                      * INTVAL (XEXP (op0, 1)))));
        !          2275: 
1.1       root     2276:          if (GET_CODE (op0) != REG)
1.1.1.2 ! root     2277:            op0 = force_operand (op0, 0);
        !          2278:          if (GET_CODE (op0) != REG)
        !          2279:            op0 = copy_to_mode_reg (mode, op0);
        !          2280: 
1.1       root     2281:          return gen_rtx (MULT, mode, op0, 
                   2282:                          gen_rtx (CONST_INT, VOIDmode,
                   2283:                                   TREE_INT_CST_LOW (TREE_OPERAND (exp, 1))));
                   2284:        }
                   2285:       subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1));
                   2286:       /* Check for multiplying things that have been extended
                   2287:         from a narrower type.  If this machine supports multiplying
                   2288:         in that narrower type with a result in the desired type,
                   2289:         do it that way, and avoid the explicit type-conversion.  */
                   2290:       if (TREE_CODE (TREE_OPERAND (exp, 0)) == NOP_EXPR
                   2291:          && TREE_CODE (TREE_TYPE (exp)) == INTEGER_TYPE
                   2292:          && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
                   2293:              < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0))))
                   2294:          && ((TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
                   2295:               && int_fits_type_p (TREE_OPERAND (exp, 1),
1.1.1.2 ! root     2296:                                   TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
        !          2297:               /* Don't use a widening multiply if a shift will do.  */
        !          2298:               && exact_log2 (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1))) < 0)
1.1       root     2299:              ||
                   2300:              (TREE_CODE (TREE_OPERAND (exp, 1)) == NOP_EXPR
                   2301:               && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 1), 0)))
                   2302:                   ==
1.1.1.2 ! root     2303:                   TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))))
        !          2304:               /* If both operands are extended, they must either both
        !          2305:                  be zero-extended or both be sign-extended.  */
        !          2306:               && (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 1), 0)))
        !          2307:                   ==
        !          2308:                   TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))))))
1.1       root     2309:        {
                   2310:          enum machine_mode innermode
                   2311:            = TYPE_MODE (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)));
1.1.1.2 ! root     2312:          this_optab = (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
1.1       root     2313:                        ? umul_widen_optab : smul_widen_optab);
                   2314:          if ((int) innermode + 1 == (int) mode
1.1.1.2 ! root     2315:              && this_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
1.1       root     2316:            {
                   2317:              op0 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
                   2318:                                 0, VOIDmode, 0);
                   2319:              if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
                   2320:                op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
                   2321:              else
                   2322:                op1 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 1), 0),
                   2323:                                   0, VOIDmode, 0);
                   2324:              goto binop2;
                   2325:            }
                   2326:        }
                   2327:       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
                   2328:       op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
1.1.1.2 ! root     2329:       return expand_mult (mode, op0, op1, target, TREE_UNSIGNED (type));
1.1       root     2330: 
                   2331:     case TRUNC_DIV_EXPR:
                   2332:     case FLOOR_DIV_EXPR:
                   2333:     case CEIL_DIV_EXPR:
                   2334:     case ROUND_DIV_EXPR:
                   2335:       preexpand_calls (exp);
                   2336:       subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1));
1.1.1.2 ! root     2337:       /* Possible optimization: compute the dividend with EXPAND_SUM
1.1       root     2338:         then if the divisor is constant can optimize the case
                   2339:         where some terms of the dividend have coeffs divisible by it.  */
                   2340:       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
                   2341:       op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
                   2342:       return expand_divmod (0, code, mode, op0, op1, target,
1.1.1.2 ! root     2343:                            TREE_UNSIGNED (type));
1.1       root     2344: 
                   2345:     case RDIV_EXPR:
                   2346:       preexpand_calls (exp);
                   2347:       this_optab = flodiv_optab;
                   2348:       goto binop;
                   2349: 
                   2350:     case TRUNC_MOD_EXPR:
                   2351:     case FLOOR_MOD_EXPR:
                   2352:     case CEIL_MOD_EXPR:
                   2353:     case ROUND_MOD_EXPR:
                   2354:       preexpand_calls (exp);
                   2355:       subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1));
                   2356:       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
                   2357:       op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
                   2358:       return expand_divmod (1, code, mode, op0, op1, target,
1.1.1.2 ! root     2359:                            TREE_UNSIGNED (type));
1.1       root     2360: #if 0
                   2361: #ifdef HAVE_divmoddisi4
                   2362:       if (GET_MODE (op0) != DImode)
                   2363:        {
                   2364:          temp = gen_reg_rtx (DImode);
                   2365:          convert_move (temp, op0, 0);
                   2366:          op0 = temp;
                   2367:          if (GET_MODE (op1) != SImode && GET_CODE (op1) != CONST_INT)
                   2368:            {
                   2369:              temp = gen_reg_rtx (SImode);
                   2370:              convert_move (temp, op1, 0);
                   2371:              op1 = temp;
                   2372:            }
                   2373:          temp = gen_reg_rtx (SImode);
                   2374:          if (target == 0)
                   2375:            target = gen_reg_rtx (SImode);
                   2376:          emit_insn (gen_divmoddisi4 (temp, protect_from_queue (op0, 0),
                   2377:                                      protect_from_queue (op1, 0),
                   2378:                                      protect_from_queue (target, 1)));
                   2379:          return target;
                   2380:        }
                   2381: #endif
                   2382: #endif
                   2383: 
                   2384:     case FIX_ROUND_EXPR:
                   2385:     case FIX_FLOOR_EXPR:
                   2386:     case FIX_CEIL_EXPR:
                   2387:       abort ();                        /* Not used for C.  */
                   2388: 
                   2389:     case FIX_TRUNC_EXPR:
                   2390:       op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
                   2391:       if (target == 0)
                   2392:        target = gen_reg_rtx (mode);
1.1.1.2 ! root     2393:       {
        !          2394:        int unsignedp = TREE_UNSIGNED (TREE_TYPE (exp));
        !          2395:        if (mode == HImode || mode == QImode)
        !          2396:          {
        !          2397:            register rtx temp = gen_reg_rtx (SImode);
        !          2398:            expand_fix (temp, op0, unsignedp);
        !          2399:            convert_move (target, temp, unsignedp);
        !          2400:          }
        !          2401:        else
        !          2402:          expand_fix (target, op0, unsignedp);
        !          2403:       }
1.1       root     2404:       return target;
                   2405: 
                   2406:     case FLOAT_EXPR:
                   2407:       op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
                   2408:       if (target == 0)
                   2409:        target = gen_reg_rtx (mode);
1.1.1.2 ! root     2410:       {
        !          2411:        int unsignedp = TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0)));
        !          2412:        if (GET_MODE (op0) == HImode
        !          2413:            || GET_MODE (op0) == QImode)
        !          2414:          {
        !          2415:            register rtx temp = gen_reg_rtx (SImode);
        !          2416:            convert_move (temp, op0, unsignedp);
        !          2417:            expand_float (target, temp, 0);
        !          2418:          }
        !          2419:        else
        !          2420:          expand_float (target, op0, unsignedp);
        !          2421:       }
1.1       root     2422:       return target;
                   2423: 
                   2424:     case NEGATE_EXPR:
                   2425:       op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0);
                   2426:       temp = expand_unop (mode, neg_optab, op0, target, 0);
                   2427:       if (temp == 0)
                   2428:        abort ();
                   2429:       return temp;
                   2430: 
                   2431:     case ABS_EXPR:
                   2432:       /* First try to do it with a special abs instruction.
                   2433:         If that does not win, use conditional jump and negate.  */
1.1.1.2 ! root     2434:       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
1.1       root     2435:       temp = expand_unop (mode, abs_optab, op0, target, 0);
                   2436:       if (temp != 0)
                   2437:        return temp;
                   2438:       temp = gen_label_rtx ();
                   2439:       if (target == 0 || GET_CODE (target) != REG)
1.1.1.2 ! root     2440:        target = gen_reg_rtx (mode);
1.1       root     2441:       emit_move_insn (target, op0);
1.1.1.2 ! root     2442:       emit_cmp_insn (target,
        !          2443:                     expand_expr (convert (TREE_TYPE (exp), integer_zero_node),
        !          2444:                                  0, VOIDmode, 0),
        !          2445:                     0, 0);
1.1       root     2446:       emit_jump_insn (gen_bge (temp));
                   2447:       op0 = expand_unop (mode, neg_optab, target, target, 0);
                   2448:       if (op0 != target)
                   2449:        emit_move_insn (target, op0);
                   2450:       emit_label (temp);
                   2451:       return target;
                   2452: 
                   2453:     case MAX_EXPR:
                   2454:     case MIN_EXPR:
1.1.1.2 ! root     2455:       mode = TYPE_MODE (TREE_OPERAND (exp, 1));
1.1       root     2456:       op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
                   2457:       if (target == 0 || GET_CODE (target) != REG || target == op1)
1.1.1.2 ! root     2458:        target = gen_reg_rtx (mode);
1.1       root     2459:       op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0);
                   2460:       if (target != op0)
                   2461:        emit_move_insn (target, op0);
                   2462:       op0 = gen_label_rtx ();
                   2463:       if (code == MAX_EXPR)
1.1.1.2 ! root     2464:        temp = (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 1)))
        !          2465:                ? compare1 (target, op1, GEU, LEU, 1, mode)
        !          2466:                : compare1 (target, op1, GE, LE, 0, mode));
        !          2467:       else
        !          2468:        temp = (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 1)))
        !          2469:                ? compare1 (target, op1, LEU, GEU, 1, mode)
        !          2470:                : compare1 (target, op1, LE, GE, 0, mode));
        !          2471:       if (temp == const0_rtx)
        !          2472:        emit_move_insn (target, op1);
        !          2473:       else if (temp != const1_rtx)
        !          2474:        {
        !          2475:          emit_jump_insn (gen_rtx (SET, VOIDmode, pc_rtx,
        !          2476:                                   gen_rtx (IF_THEN_ELSE, VOIDmode,
        !          2477:                                            temp,
        !          2478:                                            gen_rtx (LABEL_REF, VOIDmode, op0),
        !          2479:                                            pc_rtx)));
        !          2480:          emit_move_insn (target, op1);
        !          2481:        }
        !          2482:       emit_label (op0);
1.1       root     2483:       return target;
                   2484: 
                   2485: /* ??? Can optimize when the operand of this is a bitwise operation,
                   2486:    by using a different bitwise operation.  */
                   2487:     case BIT_NOT_EXPR:
                   2488:       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
                   2489:       temp = expand_unop (mode, one_cmpl_optab, op0, target, 1);
                   2490:       if (temp == 0)
                   2491:        abort ();
                   2492:       return temp;
                   2493: 
1.1.1.2 ! root     2494:     case FFS_EXPR:
        !          2495:       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
        !          2496:       temp = expand_unop (mode, ffs_optab, op0, target, 1);
        !          2497:       if (temp == 0)
        !          2498:        abort ();
        !          2499:       return temp;
        !          2500: 
1.1       root     2501: /* ??? Can optimize bitwise operations with one arg constant.
                   2502:    Pastel optimizes (a bitwise1 n) bitwise2 (a bitwise3 b)
                   2503:    and (a bitwise1 b) bitwise2 b (etc)
                   2504:    but that is probably not worth while.  */
                   2505: 
1.1.1.2 ! root     2506: /* BIT_AND_EXPR is for bitwise anding.
1.1       root     2507:    TRUTH_AND_EXPR is for anding two boolean values
                   2508:    when we want in all cases to compute both of them.
                   2509:    In general it is fastest to do TRUTH_AND_EXPR by
                   2510:    computing both operands as actual zero-or-1 values
                   2511:    and then bitwise anding.  In cases where there cannot
                   2512:    be any side effects, better code would be made by
                   2513:    treating TRUTH_AND_EXPR like TRUTH_ANDIF_EXPR;
                   2514:    but the question is how to recognize those cases.  */
                   2515: 
                   2516:     case TRUTH_AND_EXPR:
                   2517:     case BIT_AND_EXPR:
                   2518:       preexpand_calls (exp);
                   2519:       subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1));
                   2520:       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
                   2521:       op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
                   2522:       return expand_bit_and (mode, op0, op1, target);
                   2523: 
                   2524: /* See comment above about TRUTH_AND_EXPR; it applies here too.  */
                   2525:     case TRUTH_OR_EXPR:
                   2526:     case BIT_IOR_EXPR:
                   2527:       preexpand_calls (exp);
                   2528:       this_optab = ior_optab;
                   2529:       goto binop;
                   2530: 
                   2531:     case BIT_XOR_EXPR:
                   2532:       preexpand_calls (exp);
                   2533:       this_optab = xor_optab;
                   2534:       goto binop;
                   2535: 
                   2536:     case LSHIFT_EXPR:
                   2537:     case RSHIFT_EXPR:
                   2538:     case LROTATE_EXPR:
                   2539:     case RROTATE_EXPR:
                   2540:       preexpand_calls (exp);
                   2541:       subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1));
                   2542:       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
                   2543:       return expand_shift (code, mode, op0, TREE_OPERAND (exp, 1), target,
1.1.1.2 ! root     2544:                           TREE_UNSIGNED (type));
1.1       root     2545: 
                   2546: /* ??? cv's were used to effect here to combine additive constants
                   2547:    and to determine the answer when only additive constants differ.
                   2548:    Also, the addition of one can be handled by changing the condition.  */
                   2549:     case LT_EXPR:
                   2550:     case LE_EXPR:
                   2551:     case GT_EXPR:
                   2552:     case GE_EXPR:
                   2553:     case EQ_EXPR:
                   2554:     case NE_EXPR:
                   2555:       preexpand_calls (exp);
1.1.1.2 ! root     2556:       temp = do_store_flag (exp, target, mode);
1.1       root     2557:       if (temp != 0)
                   2558:        return temp;
1.1.1.2 ! root     2559:       /* For foo != 0, load foo, and if it is nonzero load 1 instead. */
        !          2560:       if (code == NE_EXPR && integer_zerop (TREE_OPERAND (exp, 1))
        !          2561:          && subtarget
        !          2562:          && (GET_MODE (subtarget)
        !          2563:              == TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
1.1       root     2564:        {
                   2565:          temp = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
                   2566:          if (temp != subtarget)
                   2567:            temp = copy_to_reg (temp);
                   2568:          op1 = gen_label_rtx ();
1.1.1.2 ! root     2569:          emit_cmp_insn (temp, const0_rtx, 0, TREE_UNSIGNED (type));
1.1       root     2570:          emit_jump_insn (gen_beq (op1));
                   2571:          emit_move_insn (temp, const1_rtx);
                   2572:          emit_label (op1);
                   2573:          return temp;
                   2574:        }
                   2575:       /* If no set-flag instruction, must generate a conditional
                   2576:         store into a temporary variable.  Drop through
                   2577:         and handle this like && and ||.  */
                   2578: 
                   2579:     case TRUTH_ANDIF_EXPR:
                   2580:     case TRUTH_ORIF_EXPR:
                   2581:       temp = gen_reg_rtx (mode);
                   2582:       emit_clr_insn (temp);
                   2583:       op1 = gen_label_rtx ();
                   2584:       jumpifnot (exp, op1);
                   2585:       emit_0_to_1_insn (temp);
                   2586:       emit_label (op1);
                   2587:       return temp;
                   2588: 
                   2589:     case TRUTH_NOT_EXPR:
                   2590:       op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0);
                   2591:       /* The parser is careful to generate TRUTH_NOT_EXPR
                   2592:         only with operands that are always zero or one.  */
                   2593:       temp = expand_binop (mode, xor_optab, op0,
                   2594:                           gen_rtx (CONST_INT, mode, 1),
                   2595:                           target, 1, OPTAB_LIB_WIDEN);
                   2596:       if (temp == 0)
                   2597:        abort ();
                   2598:       return temp;
                   2599: 
                   2600:     case COMPOUND_EXPR:
1.1.1.2 ! root     2601:       expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0);
1.1       root     2602:       emit_queue ();
                   2603:       return expand_expr (TREE_OPERAND (exp, 1), target, VOIDmode, 0);
                   2604: 
                   2605:     case COND_EXPR:
                   2606:       /* Note that COND_EXPRs whose type is a structure or union
                   2607:         are required to be constructed to contain assignments of
                   2608:         a temporary variable, so that we can evaluate them here
                   2609:         for side effect only.  If type is void, we must do likewise.  */
                   2610:       op0 = gen_label_rtx ();
                   2611:       op1 = gen_label_rtx ();
                   2612: 
1.1.1.2 ! root     2613:       if (mode == VOIDmode || ignore)
1.1       root     2614:        temp = 0;
                   2615:       else if (target)
                   2616:        temp = target;
1.1.1.2 ! root     2617:       else if (mode == BLKmode)
        !          2618:        {
        !          2619:          if (TYPE_SIZE (type) == 0 || ! TREE_LITERAL (TYPE_SIZE (type)))
        !          2620:            abort ();
        !          2621:          temp = assign_stack_local (BLKmode,
        !          2622:                                     (TREE_INT_CST_LOW (TYPE_SIZE (type))
        !          2623:                                      * TYPE_SIZE_UNIT (type)
        !          2624:                                      + BITS_PER_UNIT - 1)
        !          2625:                                     / BITS_PER_UNIT);
        !          2626:        }
1.1       root     2627:       else
                   2628:        temp = gen_reg_rtx (mode);
                   2629: 
                   2630:       jumpifnot (TREE_OPERAND (exp, 0), op0);
                   2631:       current_args_size += 1;
                   2632:       if (temp != 0)
1.1.1.2 ! root     2633:        store_expr (TREE_OPERAND (exp, 1), temp, 0);
1.1       root     2634:       else
1.1.1.2 ! root     2635:        expand_expr (TREE_OPERAND (exp, 1), ignore ? const0_rtx : 0,
        !          2636:                     VOIDmode, 0);
1.1       root     2637:       emit_queue ();
                   2638:       emit_jump_insn (gen_jump (op1));
                   2639:       emit_barrier ();
                   2640:       emit_label (op0);
                   2641:       if (temp != 0)
1.1.1.2 ! root     2642:        store_expr (TREE_OPERAND (exp, 2), temp, 0);
1.1       root     2643:       else
1.1.1.2 ! root     2644:        expand_expr (TREE_OPERAND (exp, 2), ignore ? const0_rtx : 0,
        !          2645:                     VOIDmode, 0);
1.1       root     2646:       emit_queue ();
                   2647:       emit_label (op1);
                   2648:       current_args_size -= 1;
                   2649:       return temp;
                   2650: 
                   2651:     case MODIFY_EXPR:
                   2652:       /* If lhs is complex, expand calls in rhs before computing it.
                   2653:         That's so we don't compute a pointer and save it over a call.
                   2654:         If lhs is simple, compute it first so we can give it as a
                   2655:         target if the rhs is just a call.  This avoids an extra temp and copy
                   2656:         and that prevents a partial-subsumption which makes bad code.
                   2657:         Actually we could treat component_ref's of vars like vars.  */
1.1.1.2 ! root     2658:       if (TREE_CODE (TREE_OPERAND (exp, 0)) != VAR_DECL
        !          2659:          && TREE_CODE (TREE_OPERAND (exp, 0)) != RESULT_DECL
        !          2660:          && TREE_CODE (TREE_OPERAND (exp, 0)) != PARM_DECL)
1.1       root     2661:        preexpand_calls (exp);
                   2662:       temp = expand_assignment (TREE_OPERAND (exp, 0),
1.1.1.2 ! root     2663:                                TREE_OPERAND (exp, 1),
        !          2664:                                ! ignore,
        !          2665:                                original_target != 0);
1.1       root     2666:       return temp;
                   2667: 
                   2668:     case PREINCREMENT_EXPR:
                   2669:     case PREDECREMENT_EXPR:
1.1.1.2 ! root     2670:       return expand_increment (exp, 0);
1.1       root     2671: 
                   2672:     case POSTINCREMENT_EXPR:
                   2673:     case POSTDECREMENT_EXPR:
1.1.1.2 ! root     2674:       return expand_increment (exp, 1);
1.1       root     2675: 
                   2676:     case ADDR_EXPR:
1.1.1.2 ! root     2677:       op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode,
        !          2678:                         EXPAND_CONST_ADDRESS);
1.1       root     2679:       if (GET_CODE (op0) != MEM)
                   2680:        abort ();
1.1.1.2 ! root     2681:       if (modifier == EXPAND_SUM)
1.1       root     2682:        return XEXP (op0, 0);
1.1.1.2 ! root     2683:       op0 = force_operand (XEXP (op0, 0), target);
        !          2684:       if (flag_force_addr && GET_CODE (op0) != REG)
        !          2685:        return force_reg (Pmode, op0);
        !          2686:       return op0;
1.1       root     2687: 
                   2688:     case ENTRY_VALUE_EXPR:
                   2689:       abort ();
                   2690: 
                   2691:     case ERROR_MARK:
1.1.1.2 ! root     2692:       return const0_rtx;
1.1       root     2693: 
                   2694:     default:
                   2695:       abort ();
                   2696:     }
                   2697: 
                   2698:   /* Here to do an ordinary binary operator, generating an instruction
                   2699:      from the optab already placed in `this_optab'.  */
                   2700:  binop:
                   2701:   /* Detect things like x = y | (a == b)
                   2702:      and do them as (x = y), (a == b ? x |= 1 : 0), x.  */
                   2703:   /* First, get the comparison or conditional into the second arg.  */
                   2704:   if (comparison_code[(int) TREE_CODE (TREE_OPERAND (exp, 0))]
                   2705:       || (TREE_CODE (TREE_OPERAND (exp, 0)) == COND_EXPR
                   2706:          && (integer_zerop (TREE_OPERAND (TREE_OPERAND (exp, 0), 1))
                   2707:              || integer_zerop (TREE_OPERAND (TREE_OPERAND (exp, 0), 2)))))
                   2708:     {
                   2709:       if (this_optab == ior_optab || this_optab == add_optab
                   2710:          || this_optab == xor_optab)
                   2711:        {
                   2712:          tree exch = TREE_OPERAND (exp, 1);
                   2713:          TREE_OPERAND (exp, 1) = TREE_OPERAND (exp, 0);
                   2714:          TREE_OPERAND (exp, 0) = exch;
                   2715:        }
                   2716:     }
                   2717:   if (comparison_code[(int) TREE_CODE (TREE_OPERAND (exp, 1))]
                   2718:       || (TREE_CODE (TREE_OPERAND (exp, 1)) == COND_EXPR
                   2719:          && (integer_zerop (TREE_OPERAND (TREE_OPERAND (exp, 1), 1))
                   2720:              || integer_zerop (TREE_OPERAND (TREE_OPERAND (exp, 1), 2)))))
                   2721:     {
                   2722:       if (this_optab == ior_optab || this_optab == add_optab
                   2723:          || this_optab == xor_optab || this_optab == sub_optab
                   2724:          || this_optab == lshl_optab || this_optab == ashl_optab
                   2725:          || this_optab == lshr_optab || this_optab == ashr_optab
                   2726:          || this_optab == rotl_optab || this_optab == rotr_optab)
                   2727:        {
1.1.1.2 ! root     2728:          tree thenexp;
1.1       root     2729:          rtx thenv = 0;
                   2730: 
                   2731:          if (target == 0) target = gen_reg_rtx (mode);
1.1.1.2 ! root     2732:          store_expr (TREE_OPERAND (exp, 0), target, 0);
1.1       root     2733:          op0 = gen_label_rtx ();
                   2734: 
                   2735:          if (TREE_CODE (TREE_OPERAND (exp, 1)) != COND_EXPR)
                   2736:            {
                   2737:              do_jump (TREE_OPERAND (exp, 1), op0, 0);
                   2738:              thenv = const1_rtx;
                   2739:            }
                   2740:          else if (integer_zerop (TREE_OPERAND (TREE_OPERAND (exp, 1), 2)))
                   2741:            {
                   2742:              do_jump (TREE_OPERAND (TREE_OPERAND (exp, 1), 0), op0, 0);
                   2743:              thenexp = TREE_OPERAND (TREE_OPERAND (exp, 1), 1);
                   2744:            }
                   2745:          else
                   2746:            {
                   2747:              do_jump (TREE_OPERAND (TREE_OPERAND (exp, 1), 0), 0, op0);
                   2748:              thenexp = TREE_OPERAND (TREE_OPERAND (exp, 1), 2);
                   2749:            }
                   2750: 
                   2751:          if (thenv == 0)
                   2752:            thenv = expand_expr (thenexp, 0, VOIDmode, 0);
                   2753: 
                   2754:          if (this_optab == rotl_optab || this_optab == rotr_optab)
                   2755:            temp = expand_binop (mode, this_optab, target, thenv, target,
                   2756:                                 -1, OPTAB_LIB);
                   2757:          else if (this_optab == lshl_optab || this_optab == lshr_optab)
                   2758:            temp = expand_binop (mode, this_optab, target, thenv, target,
                   2759:                                 1, OPTAB_LIB_WIDEN);
                   2760:          else
                   2761:            temp = expand_binop (mode, this_optab, target, thenv, target,
                   2762:                                 0, OPTAB_LIB_WIDEN);
                   2763:          if (target != temp)
                   2764:            emit_move_insn (target, temp);
                   2765: 
                   2766:          emit_label (op0);
                   2767:          return target;
                   2768:        }
                   2769:     }
                   2770:   subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1));
                   2771:   op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
                   2772:   op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
                   2773:  binop2:
                   2774:   temp = expand_binop (mode, this_optab, op0, op1, target,
1.1.1.2 ! root     2775:                       TREE_UNSIGNED (TREE_TYPE (exp)), OPTAB_LIB_WIDEN);
1.1       root     2776:  binop1:
                   2777:   if (temp == 0)
                   2778:     abort ();
                   2779:   return temp;
                   2780: }
                   2781: 
1.1.1.2 ! root     2782: /* Expand an expression EXP that calls a built-in function,
        !          2783:    with result going to TARGET if that's convenient
        !          2784:    (and in mode MODE if that's convenient).
        !          2785:    SUBTARGET may be used as the target for computing one of EXP's operands.  */
        !          2786: 
        !          2787: static rtx
        !          2788: expand_builtin (exp, target, subtarget, mode)
        !          2789:      tree exp;
        !          2790:      rtx target;
        !          2791:      rtx subtarget;
        !          2792:      enum machine_mode mode;
        !          2793: {
        !          2794:   tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
        !          2795:   tree arglist = TREE_OPERAND (exp, 1);
        !          2796:   rtx op0;
        !          2797:   rtx temp;
        !          2798: 
        !          2799:   switch (DECL_FUNCTION_CODE (fndecl))
        !          2800:     {
        !          2801:     case BUILT_IN_ABS:
        !          2802:     case BUILT_IN_LABS:
        !          2803:     case BUILT_IN_FABS:
        !          2804:       /* build_function_call changes these into ABS_EXPR.  */
        !          2805:       abort ();
        !          2806: 
        !          2807:     case BUILT_IN_ALLOCA:
        !          2808:       if (arglist == 0)
        !          2809:        return const0_rtx;
        !          2810:       frame_pointer_needed = 1;
        !          2811:       /* Compute the argument.  */
        !          2812:       op0 = expand_expr (TREE_VALUE (arglist), 0, VOIDmode, 0);
        !          2813:       if (! CONSTANT_P (op0))
        !          2814:        {
        !          2815:          op0 = force_reg (GET_MODE (op0), op0);
        !          2816:          if (GET_MODE (op0) != Pmode)
        !          2817:            op0 = convert_to_mode (Pmode, op0);
        !          2818:        }
        !          2819:       /* Push that much space (rounding it up).  */
        !          2820:       anti_adjust_stack (round_push (op0));
        !          2821:       /* Return a copy of current stack ptr, in TARGET if possible.  */
        !          2822:       if (target)
        !          2823:        emit_move_insn (target, stack_pointer_rtx);
        !          2824:       else
        !          2825:        target = copy_to_reg (stack_pointer_rtx);
        !          2826:       return target;
        !          2827: 
        !          2828:     case BUILT_IN_FFS:
        !          2829:       if (arglist == 0)
        !          2830:        return const0_rtx;
        !          2831: 
        !          2832:       /* Compute the argument.  */
        !          2833:       op0 = expand_expr (TREE_VALUE (arglist), subtarget, VOIDmode, 0);
        !          2834:       /* Compute ffs, into TARGET if possible.
        !          2835:         Set TARGET to wherever the result comes back.  */
        !          2836:       target = expand_unop (mode, ffs_optab, op0, target, 1);
        !          2837:       if (target == 0)
        !          2838:        abort ();
        !          2839:       return target;
        !          2840: 
        !          2841:     default:
        !          2842:       abort ();
        !          2843:     }
        !          2844: }
        !          2845: 
        !          2846: /* Expand code for a post- or pre- increment or decrement
        !          2847:    and return the RTX for the result.
        !          2848:    POST is 1 for postinc/decrements and 0 for preinc/decrements.  */
        !          2849: 
        !          2850: static rtx
        !          2851: expand_increment (exp, post)
        !          2852:      register tree exp;
        !          2853:      int post;
        !          2854: {
        !          2855:   register rtx op0, op1;
        !          2856:   register rtx temp;
        !          2857:   register tree incremented = TREE_OPERAND (exp, 0);
        !          2858:   optab this_optab = add_optab;
        !          2859:   int icode;
        !          2860:   enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
        !          2861:   int op0_is_copy = 0;
        !          2862: 
        !          2863:   /* Stabilize any component ref that might need to be
        !          2864:      evaluated more than once below.  */
        !          2865:   if (TREE_CODE (incremented) == COMPONENT_REF
        !          2866:       && (TREE_CODE (TREE_OPERAND (incremented, 0)) != INDIRECT_REF
        !          2867:          || DECL_MODE (TREE_OPERAND (exp, 1)) == BImode))
        !          2868:     incremented = stabilize_reference (incremented);
        !          2869: 
        !          2870:   /* Compute the operands as RTX.
        !          2871:      Note whether OP0 is the actual lvalue or a copy of it:
        !          2872:      I believe it is a copy iff it is a register and insns were
        !          2873:      generated in computing it.  */
        !          2874:   temp = get_last_insn ();
        !          2875:   op0 = expand_expr (incremented, 0, VOIDmode, 0);
        !          2876:   if (temp != get_last_insn ())
        !          2877:     op0_is_copy = (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG);
        !          2878:   op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
        !          2879: 
        !          2880:   /* Decide whether incrementing or decrementing.  */
        !          2881:   if (TREE_CODE (exp) == POSTDECREMENT_EXPR
        !          2882:       || TREE_CODE (exp) == PREDECREMENT_EXPR)
        !          2883:     this_optab = sub_optab;
        !          2884: 
        !          2885:   /* If OP0 is not the actual lvalue, but rather a copy in a register,
        !          2886:      then we cannot just increment OP0.  We must
        !          2887:      therefore contrive to increment the original value.
        !          2888:      Then we can return OP0 since it is a copy of the old value.  */
        !          2889:   if (op0_is_copy)
        !          2890:     {
        !          2891:       /* This is the easiest way to increment the value wherever it is.
        !          2892:         Problems with multiple evaluation of INCREMENTED
        !          2893:         are prevented because either (1) it is a component_ref,
        !          2894:         in which case it was stabilized above, or (2) it is an array_ref
        !          2895:         with constant index in an array in a register, which is
        !          2896:         safe to reevaluate.  */
        !          2897:       tree newexp = build ((this_optab == add_optab
        !          2898:                            ? PLUS_EXPR : MINUS_EXPR),
        !          2899:                           TREE_TYPE (exp),
        !          2900:                           incremented,
        !          2901:                           TREE_OPERAND (exp, 1));
        !          2902:       temp = expand_assignment (incremented, newexp, ! post, 0);
        !          2903:       return post ? op0 : temp;
        !          2904:     }
        !          2905: 
        !          2906:   /* Convert decrement by a constant into a negative increment.  */
        !          2907:   if (this_optab == sub_optab
        !          2908:       && GET_CODE (op1) == CONST_INT)
        !          2909:     {
        !          2910:       op1 = gen_rtx (CONST_INT, VOIDmode, - INTVAL (op1));
        !          2911:       this_optab = add_optab;
        !          2912:     }
        !          2913: 
        !          2914:   if (post)
        !          2915:     {
        !          2916:       /* We have a true reference to the value in OP0.
        !          2917:         If there is an insn to add or subtract in this mode, queue it.  */
        !          2918: 
        !          2919:       /* I'm not sure this is still necessary.  */
        !          2920:       op0 = stabilize (op0);
        !          2921: 
        !          2922:       icode = (int) this_optab->handlers[(int) mode].insn_code;
        !          2923:       if (icode != (int) CODE_FOR_nothing
        !          2924:          /* Make sure that OP0 is valid for operands 0 and 1
        !          2925:             of the insn we want to queue.  */
        !          2926:          && (*insn_operand_predicate[icode][0]) (op0, mode)
        !          2927:          && (*insn_operand_predicate[icode][1]) (op0, mode))
        !          2928:        {
        !          2929:          if (! (*insn_operand_predicate[icode][2]) (op1, mode))
        !          2930:            op1 = force_reg (mode, op1);
        !          2931: 
        !          2932:          return enqueue_insn (op0, GEN_FCN (icode) (op0, op0, op1));
        !          2933:        }
        !          2934:     }
        !          2935: 
        !          2936:   /* Preincrement, or we can't increment with one simple insn.  */
        !          2937:   if (post)
        !          2938:     /* Save a copy of the value before inc or dec, to return it later.  */
        !          2939:     temp = copy_to_reg (op0);
        !          2940:   else
        !          2941:     /* Arrange to return the incremented value.  */
        !          2942:     temp = op0;
        !          2943: 
        !          2944:   /* Increment however we can.  */
        !          2945:   op1 = expand_binop (mode, this_optab, op0, op1, op0,
        !          2946:                      0, OPTAB_LIB_WIDEN);
        !          2947:   /* Make sure the value is stored into OP0.  */
        !          2948:   if (op1 != op0)
        !          2949:     emit_move_insn (op0, op1);
        !          2950: 
        !          2951:   return temp;
        !          2952: }
        !          2953: 
1.1       root     2954: /* Expand all function calls contained within EXP, innermost ones first.
                   2955:    But don't look within expressions that have sequence points.
                   2956:    For each CALL_EXPR, record the rtx for its value
1.1.1.2 ! root     2957:    in the CALL_EXPR_RTL field.
        !          2958: 
        !          2959:    Calls that return large structures for which a structure return
        !          2960:    stack slot is needed are not preexpanded.  Preexpanding them loses
        !          2961:    because if more than one were preexpanded they would try to use the
        !          2962:    same stack slot.  */
1.1       root     2963: 
                   2964: static void
                   2965: preexpand_calls (exp)
                   2966:      tree exp;
                   2967: {
                   2968:   register int nops, i;
                   2969: 
                   2970:   if (! do_preexpand_calls)
                   2971:     return;
                   2972: 
1.1.1.2 ! root     2973:   /* Only expressions and references can contain calls.  */
        !          2974: 
        !          2975:   if (tree_code_type[(int) TREE_CODE (exp)][0] != 'e'
        !          2976:       && tree_code_type[(int) TREE_CODE (exp)][0] != 'r')
        !          2977:     return;
        !          2978: 
1.1       root     2979:   switch (TREE_CODE (exp))
                   2980:     {
                   2981:     case CALL_EXPR:
1.1.1.2 ! root     2982:       /* Do nothing to built-in functions.  */
        !          2983:       if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
        !          2984:          && TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) == FUNCTION_DECL
        !          2985:          && DECL_FUNCTION_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
        !          2986:        return;
        !          2987:       if (CALL_EXPR_RTL (exp) == 0
        !          2988:          && TYPE_MODE (TREE_TYPE (exp)) != BLKmode)
        !          2989:        CALL_EXPR_RTL (exp) = expand_call (exp, 0, 0);
1.1       root     2990:       return;
                   2991: 
                   2992:     case COMPOUND_EXPR:
                   2993:     case COND_EXPR:
                   2994:     case TRUTH_ANDIF_EXPR:
                   2995:     case TRUTH_ORIF_EXPR:
                   2996:       /* If we find one of these, then we can be sure
                   2997:         the adjust will be done for it (since it makes jumps).
                   2998:         Do it now, so that if this is inside an argument
                   2999:         of a function, we don't get the stack adjustment
                   3000:         after some other args have already been pushed.  */
                   3001:       do_pending_stack_adjust ();
                   3002:       return;
                   3003: 
1.1.1.2 ! root     3004:     case RTL_EXPR:
        !          3005:       return;
        !          3006: 
1.1       root     3007:     case SAVE_EXPR:
                   3008:       if (SAVE_EXPR_RTL (exp) != 0)
                   3009:        return;
                   3010:     }
                   3011: 
                   3012:   nops = tree_code_length[(int) TREE_CODE (exp)];
                   3013:   for (i = 0; i < nops; i++)
                   3014:     if (TREE_OPERAND (exp, i) != 0)
                   3015:       {
                   3016:        register int type = *tree_code_type[(int) TREE_CODE (TREE_OPERAND (exp, i))];
                   3017:        if (type == 'e' || type == 'r')
                   3018:          preexpand_calls (TREE_OPERAND (exp, i));
                   3019:       }
                   3020: }
                   3021: 
1.1.1.2 ! root     3022: /* Force FUNEXP into a form suitable for the address of a CALL,
        !          3023:    and return that as an rtx.  Also load the static chain register
        !          3024:    from either FUNEXP or CONTEXT.  */
1.1       root     3025: 
1.1.1.2 ! root     3026: static rtx
        !          3027: prepare_call_address (funexp, context)
1.1       root     3028:      rtx funexp;
                   3029:      rtx context;
                   3030: {
                   3031:   funexp = protect_from_queue (funexp, 0);
1.1.1.2 ! root     3032:   if (context != 0)
1.1       root     3033:     context = protect_from_queue (context, 0);
                   3034: 
                   3035:   /* Function variable in language with nested functions.  */
                   3036:   if (GET_MODE (funexp) == EPmode)
                   3037:     {
1.1.1.2 ! root     3038:       emit_move_insn (static_chain_rtx, gen_highpart (Pmode, funexp));
        !          3039:       funexp = memory_address (FUNCTION_MODE, gen_lowpart (Pmode, funexp));
        !          3040:       emit_insn (gen_rtx (USE, VOIDmode, static_chain_rtx));
1.1       root     3041:     }
                   3042:   else
                   3043:     {
                   3044:       if (context != 0)
1.1.1.2 ! root     3045:        /* Unless function variable in C, or top level function constant */
        !          3046:        emit_move_insn (static_chain_rtx, lookup_static_chain (context));
        !          3047: 
        !          3048:       /* Make a valid memory address and copy constants thru pseudo-regs,
        !          3049:         but not for a constant address if -fno-function-cse.  */
        !          3050:       if (GET_CODE (funexp) != SYMBOL_REF)
        !          3051:        funexp = memory_address (FUNCTION_MODE, funexp);
        !          3052:       else
1.1       root     3053:        {
1.1.1.2 ! root     3054: #ifndef NO_FUNCTION_CSE
        !          3055:          if (! flag_no_function_cse)
        !          3056:            funexp = copy_to_mode_reg (Pmode, funexp);
        !          3057: #endif
        !          3058:        }
        !          3059: 
        !          3060:       if (context != 0)
        !          3061:        emit_insn (gen_rtx (USE, VOIDmode, static_chain_rtx));
1.1       root     3062:     }
1.1.1.2 ! root     3063:   return funexp;
        !          3064: }
        !          3065: 
        !          3066: /* Generate instructions to call function FUNEXP,
        !          3067:    and optionally pop the results.
        !          3068:    The CALL_INSN is the first insn generated.
        !          3069: 
        !          3070:    FUNTYPE is the data type of the function, or, for a library call,
        !          3071:    the identifier for the name of the call.  This is given to the
        !          3072:    macro RETURN_POPS_ARGS to determine whether this function pops its own args.
        !          3073: 
        !          3074:    STACK_SIZE is the number of bytes of arguments on the stack, 
        !          3075:    rounded up to STACK_BOUNDARY; zero if the size is variable.
        !          3076:    This is both to put into the call insn and
        !          3077:    to generate explicit popping code if necessary.
        !          3078: 
        !          3079:    NEXT_ARG_REG is the rtx that results from executing
        !          3080:      FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1)
        !          3081:    just after all the args have had their registers assigned.
        !          3082:    This could be whatever you like, but normally it is the first
        !          3083:    arg-register beyond those used for args in this call,
        !          3084:    or 0 if all the arg-registers are used in this call.
        !          3085:    It is passed on to `gen_call' so you can put this info in the call insn.
        !          3086: 
        !          3087:    VALREG is a hard register in which a value is returned,
        !          3088:    or 0 if the call does not return a value.
        !          3089: 
        !          3090:    OLD_ARGS_SIZE is the value that `current_args_size' had before
        !          3091:    the args to this call were processed.
        !          3092:    We restore `current_args_size' to that value.  */
        !          3093: 
        !          3094: static void
        !          3095: emit_call_1 (funexp, funtype, stack_size, next_arg_reg, valreg, old_args_size)
        !          3096:      rtx funexp;
        !          3097:      tree funtype;
        !          3098:      int stack_size;
        !          3099:      rtx next_arg_reg;
        !          3100:      rtx valreg;
        !          3101:      int old_args_size;
        !          3102: {
        !          3103:   rtx stack_size_rtx = gen_rtx (CONST_INT, VOIDmode, stack_size);
        !          3104: 
        !          3105:   if (valreg)
        !          3106:     emit_call_insn (gen_call_value (valreg,
        !          3107:                                    gen_rtx (MEM, FUNCTION_MODE, funexp),
        !          3108:                                    stack_size_rtx, next_arg_reg));
        !          3109:   else
        !          3110:     emit_call_insn (gen_call (gen_rtx (MEM, FUNCTION_MODE, funexp),
        !          3111:                              stack_size_rtx, next_arg_reg));
        !          3112: 
        !          3113:   current_args_size = old_args_size;
        !          3114: 
1.1       root     3115:   /* If returning from the subroutine does not automatically pop the args,
                   3116:      we need an instruction to pop them sooner or later.
                   3117:      Perhaps do it now; perhaps just record how much space to pop later.  */
1.1.1.2 ! root     3118: 
        !          3119:   if (! RETURN_POPS_ARGS (TREE_TYPE (funtype))
        !          3120:       && stack_size != 0)
1.1       root     3121:     {
1.1.1.2 ! root     3122:       if (flag_defer_pop && current_args_size == 0)
        !          3123:        pending_stack_adjust += stack_size;
1.1       root     3124:       else
1.1.1.2 ! root     3125:        adjust_stack (gen_rtx (CONST_INT, VOIDmode, stack_size));
1.1       root     3126:     }
                   3127: }
                   3128: 
                   3129: /* At the start of a function, record that we have no previously-pushed
                   3130:    arguments waiting to be popped.  */
                   3131: 
1.1.1.2 ! root     3132: void
        !          3133: init_pending_stack_adjust ()
1.1       root     3134: {
                   3135:   pending_stack_adjust = 0;
                   3136: }
                   3137: 
1.1.1.2 ! root     3138: /* When exiting from function, if safe, clear out any pending stack adjust
        !          3139:    so the adjustment won't get done.  */
        !          3140: 
        !          3141: void
        !          3142: clear_pending_stack_adjust ()
        !          3143: {
        !          3144: #if 0
        !          3145:   /* Right now it's never considered safe, because
        !          3146:      it loses in an inline function.  */
        !          3147: #ifdef EXIT_IGNORE_STACK
        !          3148:   if (!flag_omit_frame_pointer && EXIT_IGNORE_STACK)
        !          3149:     pending_stack_adjust = 0;
        !          3150: #endif
        !          3151: #endif
        !          3152: }
        !          3153: 
1.1       root     3154: /* At start of function, initialize.  */
1.1.1.2 ! root     3155: void
1.1       root     3156: clear_current_args_size ()
                   3157: {
                   3158:   current_args_size = 0;
                   3159: }
                   3160: 
                   3161: /* Pop any previously-pushed arguments that have not been popped yet.  */
                   3162: 
1.1.1.2 ! root     3163: void
1.1       root     3164: do_pending_stack_adjust ()
                   3165: {
                   3166:   if (current_args_size == 0)
                   3167:     {
                   3168:       if (pending_stack_adjust != 0)
                   3169:        adjust_stack (gen_rtx (CONST_INT, VOIDmode, pending_stack_adjust));
                   3170:       pending_stack_adjust = 0;
                   3171:     }
                   3172: }
                   3173: 
                   3174: /* Generate all the code for a function call
                   3175:    and return an rtx for its value.
                   3176:    Store the value in TARGET (specified as an rtx) if convenient.
1.1.1.2 ! root     3177:    If the value is stored in TARGET then TARGET is returned.
        !          3178:    If IGNORE is nonzero, then we ignore the value of the function call.  */
1.1       root     3179: 
                   3180: static rtx
1.1.1.2 ! root     3181: expand_call (exp, target, ignore)
1.1       root     3182:      tree exp;
                   3183:      rtx target;
1.1.1.2 ! root     3184:      int ignore;
1.1       root     3185: {
                   3186:   tree actparms = TREE_OPERAND (exp, 1);
1.1.1.2 ! root     3187:   tree funtype;
        !          3188:   rtx funexp;
        !          3189:   register tree p = TREE_OPERAND (exp, 0);
        !          3190:   struct args_size args_size;
1.1       root     3191:   register int i;
                   3192:   register tree *argvec;
1.1.1.2 ! root     3193:   rtx *regvec;
        !          3194:   rtx *valvec;
        !          3195:   int *partial;
        !          3196:   struct args_size *arg_offset;
        !          3197:   struct args_size *arg_size;
1.1       root     3198:   int num_actuals;
                   3199:   rtx structure_value_addr = 0;
1.1.1.2 ! root     3200:   tree fndecl = 0;
        !          3201:   int may_be_alloca;
        !          3202:   int inc;
        !          3203:   int is_setjmp;
        !          3204:   int is_integrable = 0;
        !          3205:   rtx argblock = 0;
        !          3206:   CUMULATIVE_ARGS args_so_far;
        !          3207:   int reg_parm_seen = 0;
        !          3208:   rtx valreg;
        !          3209:   rtx old_stack_level;
        !          3210:   int old_pending_adj;
        !          3211:   int old_current_args_size = current_args_size;
        !          3212: 
        !          3213:   /* Number of named args.  Args after this are anonymous ones
        !          3214:      and they must all go on the stack.  */
        !          3215:   int n_named_args;
        !          3216: 
        !          3217:   args_size.constant = 0;
        !          3218:   args_size.var = 0;
        !          3219: 
        !          3220:   /* See if we can find a DECL-node for the actual function.
        !          3221:      As a result, decide whether this is a call to an integrable function.  */
        !          3222: 
        !          3223:   if (TREE_CODE (p) == ADDR_EXPR)
        !          3224:     {
        !          3225:       fndecl = TREE_OPERAND (p, 0);
        !          3226:       if (TREE_CODE (fndecl) != FUNCTION_DECL)
        !          3227:        fndecl = 0;
        !          3228:       else
        !          3229:        {
        !          3230:          extern tree current_function_decl;
1.1       root     3231: 
1.1.1.2 ! root     3232:          if (fndecl != current_function_decl
        !          3233:              && DECL_SAVED_INSNS (fndecl))
        !          3234:            is_integrable = 1;
        !          3235:          else
        !          3236:            /* In case this function later becomes inlineable,
        !          3237:               record that there was already a non-inline call to it.  */
        !          3238:            TREE_ADDRESSABLE (fndecl) = 1;
        !          3239:        }
        !          3240:     }
1.1       root     3241: 
1.1.1.2 ! root     3242:   /* Set up a place to return a structure.  */
1.1       root     3243: 
                   3244:   if (TYPE_MODE (TREE_TYPE (exp)) == BLKmode)
                   3245:     {
                   3246:       /* This call returns a big structure.  */
                   3247:       if (target)
                   3248:        structure_value_addr = XEXP (target, 0);
                   3249:       else
                   3250:        /* Make room on the stack to hold the value.  */
                   3251:        structure_value_addr = get_structure_value_addr (expr_size (exp));
                   3252:     }
                   3253: 
1.1.1.2 ! root     3254:   if (is_integrable)
        !          3255:     {
        !          3256:       extern int integration_time;
        !          3257:       extern rtx expand_inline_function ();
        !          3258:       rtx temp;
        !          3259: 
        !          3260:       temp = expand_inline_function (fndecl, actparms, target,
        !          3261:                                     ignore, TREE_TYPE (exp),
        !          3262:                                     structure_value_addr);
        !          3263: 
        !          3264:       /* If the inlining failed for whatever reason, we will just
        !          3265:         issue a normal call.  */
        !          3266:       if (temp == (rtx)-1)
        !          3267:        {
        !          3268:          warning_with_decl (fndecl, "inlining function `%s' failed, reverting to function call");
        !          3269:        }
        !          3270:       else
        !          3271:        return temp;
        !          3272:     }
        !          3273: 
        !          3274: #if 0
        !          3275:   /* Unless it's a call to a specific function that isn't alloca,
        !          3276:      if it has one argument, we must assume it might be alloca.  */
        !          3277: 
        !          3278:   may_be_alloca =
        !          3279:     (!(fndecl != 0
        !          3280:        && strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)),
        !          3281:                  "alloca"))
        !          3282:      && actparms != 0
        !          3283:      && TREE_CHAIN (actparms) == 0);
        !          3284: #else
        !          3285:   /* We assume that alloca will always be called by name.  It
        !          3286:      makes no sense to pass it as a pointer-to-function to
        !          3287:      anything that does not understand its behavior.  */
        !          3288:   may_be_alloca =
        !          3289:     (fndecl && ! strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "alloca"));
        !          3290: #endif
        !          3291: 
        !          3292:   /* See if this is a call to a function that can return more than once.  */
        !          3293: 
        !          3294:   is_setjmp
        !          3295:     = (fndecl != 0
        !          3296:        && (!strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "setjmp")
        !          3297:           || !strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "_setjmp")));
        !          3298: 
        !          3299:   if (may_be_alloca)
        !          3300:     {
        !          3301:       frame_pointer_needed = 1;
        !          3302:       may_call_alloca = 1;
        !          3303:     }
        !          3304: 
        !          3305:   /* Don't let pending stack adjusts add up to too much.
        !          3306:      Also, do all pending adjustments now
        !          3307:      if there is any chance this might be a call to alloca.  */
        !          3308: 
        !          3309:   if (pending_stack_adjust >= 32
        !          3310:       || (pending_stack_adjust > 0 && may_be_alloca))
        !          3311:     do_pending_stack_adjust ();
        !          3312: 
        !          3313:   /* Operand 0 is a pointer-to-function; get the type of the function.  */
        !          3314:   funtype = TREE_TYPE (TREE_OPERAND (exp, 0));
        !          3315:   if (TREE_CODE (funtype) != POINTER_TYPE)
        !          3316:     abort ();
        !          3317:   funtype = TREE_TYPE (funtype);
        !          3318: 
        !          3319:   /* Count the arguments and set NUM_ACTUALS.  */
1.1       root     3320:   for (p = actparms, i = 0; p; p = TREE_CHAIN (p)) i++;
                   3321:   num_actuals = i;
1.1.1.2 ! root     3322: 
        !          3323:   /* Compute number of named args.
        !          3324:      This may actually be 1 too large, but that happens
        !          3325:      only in the case when all args are named, so no trouble results.  */
        !          3326:   if (TYPE_ARG_TYPES (funtype) != 0)
        !          3327:     n_named_args = list_length (TYPE_ARG_TYPES (funtype));
        !          3328:   else
        !          3329:     /* If we know nothing, treat all args as named.  */
        !          3330:     n_named_args = num_actuals;
        !          3331: 
        !          3332:   /* Make a vector of the args, in the order we want to compute them,
        !          3333:      and a parallel vector of where we want to put them.
        !          3334:      regvec[I] is 0 to if should push argvec[I] or else a reg to put it in.
        !          3335:      valvec[i] is the arg value as an rtx.  */
1.1       root     3336:   argvec = (tree *) alloca (i * sizeof (tree));
1.1.1.2 ! root     3337:   regvec = (rtx *) alloca (i * sizeof (rtx));
        !          3338:   valvec = (rtx *) alloca (i * sizeof (rtx));
        !          3339:   partial = (int *) alloca (i * sizeof (int));
        !          3340:   arg_size = (struct args_size *) alloca (i * sizeof (struct args_size));
        !          3341:   arg_offset = (struct args_size *) alloca (i * sizeof (struct args_size));
        !          3342: 
        !          3343:   /* In this loop, we consider args in the order they are written.
        !          3344:      We fill up argvec from the front of from the back
        !          3345:      so that the first arg to be pushed ends up at the front.  */
1.1       root     3346: 
1.1.1.2 ! root     3347: #ifdef PUSH_ARGS_REVERSED
        !          3348:   i = num_actuals - 1, inc = -1;
1.1       root     3349:   /* In this case, must reverse order of args
1.1.1.2 ! root     3350:      so that we compute and push the last arg first.  */
1.1       root     3351: #else
1.1.1.2 ! root     3352:   i = 0, inc = 1;
        !          3353: #endif
        !          3354: 
        !          3355:   INIT_CUMULATIVE_ARGS (args_so_far, funtype);
        !          3356: 
        !          3357:   for (p = actparms; p; p = TREE_CHAIN (p), i += inc)
        !          3358:     {
        !          3359:       tree type = TREE_TYPE (TREE_VALUE (p));
        !          3360:       argvec[i] = p;
        !          3361:       regvec[i] = 0;
        !          3362:       valvec[i] = 0;
        !          3363:       partial[i] = 0;
        !          3364:       arg_size[i].constant = 0;
        !          3365:       arg_size[i].var = 0;
        !          3366:       arg_offset[i] = args_size;
        !          3367: 
        !          3368:       if (type == error_mark_node)
        !          3369:        continue;
        !          3370: 
        !          3371:       /* Decide where to pass this arg.  */
        !          3372:       /* regvec[i] is nonzero if all or part is passed in registers.
        !          3373:         partial[i] is nonzero if part but not all is passed in registers,
        !          3374:          and the exact value says how many words are passed in registers.  */
        !          3375: 
        !          3376:       if (TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
        !          3377:          || args_size.var != 0)
        !          3378:        {
        !          3379:          regvec[i] = FUNCTION_ARG (args_so_far, TYPE_MODE (type), type,
        !          3380:                                    i < n_named_args);
        !          3381: #ifdef FUNCTION_ARG_PARTIAL_NREGS
        !          3382:          partial[i] = FUNCTION_ARG_PARTIAL_NREGS (args_so_far,
        !          3383:                                                   TYPE_MODE (type), type,
        !          3384:                                                   i < n_named_args);
        !          3385: #endif
        !          3386:        }
        !          3387: 
        !          3388:       /* Once we see at least one parm that is being passed in a register,
        !          3389:         precompute that parm and all remaining parms (if they do arithmetic)
        !          3390:         before loading any of them into their specified registers.
        !          3391:         That way we don't lose if one of them involves
        !          3392:         a function call OR a library routine that needs the same regs.  */
        !          3393:       if (regvec[i] != 0)
        !          3394:        reg_parm_seen = 1;
        !          3395: 
        !          3396:       if (reg_parm_seen)
        !          3397:        {
        !          3398:          valvec[i] = expand_expr (TREE_VALUE (p), 0, VOIDmode, 0);
        !          3399:          if (GET_CODE (valvec[i]) != MEM
        !          3400:              && ! CONSTANT_P (valvec[i])
        !          3401:              && GET_CODE (valvec[i]) != CONST_DOUBLE)
        !          3402:            valvec[i] = force_reg (TYPE_MODE (type), valvec[i]);
        !          3403:        }
        !          3404: 
        !          3405:       /* Increment ARGS_SO_FAR, which has info about which arg-registers
        !          3406:         have been used, etc.  */
        !          3407: 
        !          3408:       FUNCTION_ARG_ADVANCE (args_so_far, TYPE_MODE (type), type,
        !          3409:                            i < n_named_args);
        !          3410: 
        !          3411:       /* Increment ARGS_SIZE, which is the size of all args so far.  */
        !          3412: 
        !          3413:       if (regvec[i] != 0 && partial[i] == 0)
        !          3414:        /* A register-arg doesn't count.  */
        !          3415:        ;
        !          3416:       else if (TYPE_MODE (type) != BLKmode)
        !          3417:        {
        !          3418:          register int size;
        !          3419: 
        !          3420:          size = GET_MODE_SIZE (TYPE_MODE (type));
        !          3421:          /* Compute how much space the push instruction will push.
        !          3422:             On many machines, pushing a byte will advance the stack
        !          3423:             pointer by a halfword.  */
        !          3424: #ifdef PUSH_ROUNDING
        !          3425:          size = PUSH_ROUNDING (size);
1.1       root     3426: #endif
1.1.1.2 ! root     3427:          /* Compute how much space the argument should get:
        !          3428:             round up to a multiple of the alignment for arguments.  */
        !          3429:          arg_size[i].constant
        !          3430:            = (((size + PARM_BOUNDARY / BITS_PER_UNIT - 1)
        !          3431:                / (PARM_BOUNDARY / BITS_PER_UNIT))
        !          3432:               * (PARM_BOUNDARY / BITS_PER_UNIT));
        !          3433:        }
        !          3434:       else
        !          3435:        {
        !          3436:          register tree size = size_in_bytes (type);
        !          3437: 
        !          3438:          /* A nonscalar.  Round its size up to a multiple
        !          3439:             of the allocation unit for arguments.  */
        !          3440: 
        !          3441:          /* Now round up to multiple of PARM_BOUNDARY bits,
        !          3442:             then express as number of bytes.  */
        !          3443:          ADD_PARM_SIZE (arg_size[i],
        !          3444:                         convert_units (convert_units (size, BITS_PER_UNIT, PARM_BOUNDARY),
        !          3445:                                        PARM_BOUNDARY, BITS_PER_UNIT));
        !          3446: 
        !          3447:        }
        !          3448:       /* If a part of the arg was put into registers,
        !          3449:         don't include that part in the amount pushed.  */
        !          3450:       arg_size[i].constant
        !          3451:        -= ((partial[i] * UNITS_PER_WORD)
        !          3452:            / (PARM_BOUNDARY / BITS_PER_UNIT)
        !          3453:            * (PARM_BOUNDARY / BITS_PER_UNIT));
        !          3454: 
        !          3455:       args_size.constant += arg_size[i].constant;
        !          3456: 
        !          3457:       if (arg_size[i].var)
        !          3458:        {
        !          3459:          ADD_PARM_SIZE (args_size, arg_size[i].var);
        !          3460:        }
        !          3461:     }
        !          3462: 
        !          3463:   /* If we have no actual push instructions, or we need a variable
        !          3464:      amount of space, make space for all the args right now.
        !          3465:      In any case, round the needed size up to multiple of STACK_BOUNDARY.  */
        !          3466: 
        !          3467:   if (args_size.var != 0)
        !          3468:     {
        !          3469:       old_stack_level = copy_to_mode_reg (Pmode, stack_pointer_rtx);
        !          3470:       old_pending_adj = pending_stack_adjust;
        !          3471:       argblock = push_block (round_push (ARGS_SIZE_RTX (args_size)));
        !          3472:     }
        !          3473:   else if (args_size.constant != 0)
        !          3474:     {
        !          3475:       int needed = args_size.constant;
        !          3476: 
        !          3477: #ifdef STACK_BOUNDARY
        !          3478:       needed = (needed + STACK_BYTES - 1) / STACK_BYTES * STACK_BYTES;
        !          3479:       args_size.constant = needed;
        !          3480: #endif
        !          3481: 
        !          3482: #ifndef PUSH_ROUNDING
        !          3483:       /* Try to reuse some or all of the pending_stack_adjust
        !          3484:         to get this space.  Maybe we can avoid any pushing.  */
        !          3485:       if (needed > pending_stack_adjust)
        !          3486:        {
        !          3487:          needed -= pending_stack_adjust;
        !          3488:          pending_stack_adjust = 0;
        !          3489:        }
        !          3490:       else
        !          3491:        {
        !          3492:          pending_stack_adjust -= needed;
        !          3493:          needed = 0;
        !          3494:        }
        !          3495:       if (needed > 0)
        !          3496:        argblock = push_block (gen_rtx (CONST_INT, VOIDmode, needed));
        !          3497: #endif /* no PUSH_ROUNDING */
        !          3498:     }
        !          3499: 
        !          3500:   /* Get the function to call, in the form of RTL.  */
        !          3501:   if (fndecl)
        !          3502:     /* Get a SYMBOL_REF rtx for the function address.  */
        !          3503:     funexp = XEXP (DECL_RTL (fndecl), 0);
        !          3504:   else
        !          3505:     /* Generate an rtx (probably a pseudo-register) for the address.  */
        !          3506:     funexp = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
        !          3507: 
        !          3508:   /* Now actually compute the args, and push those that need pushing.  */
        !          3509: 
1.1       root     3510:   for (i = 0; i < num_actuals; i++)
                   3511:     {
                   3512:       register tree p = argvec[i];
                   3513:       register tree pval = TREE_VALUE (p);
1.1.1.2 ! root     3514:       int used = 0;
1.1       root     3515: 
                   3516:       /* Push the next argument.  Note that it has already been converted
                   3517:         if necessary to the type that the called function expects.  */
                   3518: 
                   3519:       if (TREE_CODE (pval) == ERROR_MARK)
                   3520:        ;
1.1.1.2 ! root     3521:       else if (regvec[i] != 0 && partial[i] == 0)
        !          3522:        {
        !          3523:          /* Being passed entirely in a register.  */
        !          3524:          if (valvec[i] != 0)
        !          3525:            {
        !          3526:              if (GET_MODE (valvec[i]) == BLKmode)
        !          3527:                move_block_to_reg (REGNO (regvec[i]), valvec[i],
        !          3528:                                   (int_size_in_bytes (TREE_TYPE (pval))
        !          3529:                                    / UNITS_PER_WORD));
        !          3530:              else
        !          3531:                emit_move_insn (regvec[i], valvec[i]);
        !          3532:            }
        !          3533:          else
        !          3534:            store_expr (pval, regvec[i], 0);
        !          3535: 
        !          3536:          /* Don't allow anything left on stack from computation
        !          3537:             of argument to alloca.  */
        !          3538:          if (may_be_alloca)
        !          3539:            do_pending_stack_adjust ();
        !          3540:        }
1.1       root     3541:       else if (TYPE_MODE (TREE_TYPE (pval)) != BLKmode)
                   3542:        {
1.1.1.2 ! root     3543:          register int size;
        !          3544:          rtx tem;
        !          3545: 
        !          3546:          /* Argument is a scalar, not entirely passed in registers.
        !          3547:             (If part is passed in registers, partial[I] says how much
        !          3548:             and emit_push_insn will take care of putting it there.)
1.1       root     3549: 
                   3550:             Push it, and if its size is less than the
                   3551:             amount of space allocated to it,
                   3552:             also bump stack pointer by the additional space.
                   3553:             Note that in C the default argument promotions
                   3554:             will prevent such mismatches.  */
                   3555: 
                   3556:          used = size = GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (pval)));
                   3557:          /* Compute how much space the push instruction will push.
                   3558:             On many machines, pushing a byte will advance the stack
                   3559:             pointer by a halfword.  */
1.1.1.2 ! root     3560: #ifdef PUSH_ROUNDING
1.1       root     3561:          size = PUSH_ROUNDING (size);
1.1.1.2 ! root     3562: #endif
1.1       root     3563:          /* Compute how much space the argument should get:
                   3564:             round up to a multiple of the alignment for arguments.  */
                   3565:          used = (((size + PARM_BOUNDARY / BITS_PER_UNIT - 1)
                   3566:                   / (PARM_BOUNDARY / BITS_PER_UNIT))
                   3567:                  * (PARM_BOUNDARY / BITS_PER_UNIT));
                   3568: 
1.1.1.2 ! root     3569:          tem = valvec[i];
        !          3570:          if (tem == 0)
        !          3571:            tem = expand_expr (pval, 0, VOIDmode, 0);
        !          3572: 
        !          3573:          /* Don't allow anything left on stack from computation
        !          3574:             of argument to alloca.  */
        !          3575:          if (may_be_alloca)
        !          3576:            do_pending_stack_adjust ();
        !          3577: 
        !          3578:          emit_push_insn (tem, TYPE_MODE (TREE_TYPE (pval)), 0, 0,
        !          3579:                          partial[i], regvec[i], used - size,
        !          3580:                          argblock, ARGS_SIZE_RTX (arg_offset[i]));
1.1       root     3581:        }
                   3582:       else
                   3583:        {
1.1.1.2 ! root     3584:          register rtx tem
        !          3585:            = valvec[i] ? valvec[i] : expand_expr (pval, 0, VOIDmode, 0);
1.1       root     3586:          register int excess;
1.1.1.2 ! root     3587:          rtx size_rtx;
1.1       root     3588: 
1.1.1.2 ! root     3589:          /* Pushing a nonscalar.
        !          3590:             If part is passed in registers, partial[I] says how much
        !          3591:             and emit_push_insn will take care of putting it there.  */
1.1       root     3592: 
1.1.1.2 ! root     3593:          /* Round its size up to a multiple
        !          3594:             of the allocation unit for arguments.  */
1.1       root     3595: 
1.1.1.2 ! root     3596:          if (arg_size[i].var != 0)
        !          3597:            {
        !          3598:              excess = 0;
        !          3599:              size_rtx = ARGS_SIZE_RTX (arg_size[i]);
        !          3600:            }
        !          3601:          else
        !          3602:            {
        !          3603:              register tree size = size_in_bytes (TREE_TYPE (pval));
        !          3604:              /* PUSH_ROUNDING has no effect on us, because
        !          3605:                 emit_push_insn for BLKmode is careful to avoid it.  */
        !          3606:              excess = arg_size[i].constant - TREE_INT_CST_LOW (size);
        !          3607:              size_rtx = expand_expr (size, 0, VOIDmode, 0);
        !          3608:            }
1.1       root     3609: 
1.1.1.2 ! root     3610:          emit_push_insn (tem, TYPE_MODE (TREE_TYPE (pval)), size_rtx,
        !          3611:                          TYPE_ALIGN (TREE_TYPE (pval)) / BITS_PER_UNIT,
        !          3612:                          partial[i], regvec[i], excess, argblock,
        !          3613:                          ARGS_SIZE_RTX (arg_offset[i]));
        !          3614:        }
1.1       root     3615: 
1.1.1.2 ! root     3616:       /* Account for the stack space thus used.  */
1.1       root     3617: 
                   3618: 
1.1.1.2 ! root     3619:       current_args_size += arg_size[i].constant;
        !          3620:       if (arg_size[i].var)
        !          3621:        current_args_size += 1;
1.1       root     3622:     }
                   3623: 
                   3624:   /* Perform postincrements before actually calling the function.  */
                   3625:   emit_queue ();
                   3626: 
                   3627:   /* Pass the function the address in which to return a structure value.  */
                   3628:   if (structure_value_addr)
1.1.1.2 ! root     3629:     emit_move_insn (struct_value_rtx, structure_value_addr);
        !          3630: 
        !          3631:   /* All arguments and registers used for the call must be set up by now!  */
1.1       root     3632: 
1.1.1.2 ! root     3633:   /* ??? Other languages need a nontrivial second argument (static chain).  */
        !          3634:   funexp = prepare_call_address (funexp, 0);
        !          3635: 
        !          3636:   /* Mark all register-parms as living through the call.
        !          3637:      ??? This is not quite correct, since it doesn't indicate
        !          3638:      that they are in use immediately before the call insn.
        !          3639:      Currently that doesn't matter since explicitly-used regs
        !          3640:      won't be used for reloading.  But if the reloader becomes smarter,
        !          3641:      this will have to change somehow.  */
        !          3642:   for (i = 0; i < num_actuals; i++)
        !          3643:     if (regvec[i] != 0)
        !          3644:       {
        !          3645:        if (partial[i] > 0)
        !          3646:          use_regs (REGNO (regvec[i]), partial[i]);
        !          3647:        else if (GET_MODE (regvec[i]) == BLKmode)
        !          3648:          use_regs (REGNO (regvec[i]),
        !          3649:                    (int_size_in_bytes (TREE_TYPE (TREE_VALUE (argvec[i])))
        !          3650:                     / UNITS_PER_WORD));
        !          3651:        else
        !          3652:          emit_insn (gen_rtx (USE, VOIDmode, regvec[i]));
        !          3653:       }
        !          3654: 
        !          3655:   if (structure_value_addr)
        !          3656:     emit_insn (gen_rtx (USE, VOIDmode, struct_value_rtx));
        !          3657: 
        !          3658:   /* Figure out the register where the value, if any, will come back.  */
        !          3659:   valreg = 0;
        !          3660:   if (TYPE_MODE (TREE_TYPE (exp)) != VOIDmode
        !          3661:       && TYPE_MODE (TREE_TYPE (exp)) != BLKmode)
        !          3662:     valreg = hard_function_value (TREE_TYPE (exp), fndecl);
        !          3663: 
        !          3664:   /* Generate the actual call instruction.  */
        !          3665:   emit_call_1 (funexp, funtype, args_size.constant,
        !          3666:               FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1),
        !          3667:               valreg, old_current_args_size);
1.1       root     3668: 
                   3669: /* ???  Nothing has been done here to record control flow
                   3670:    when contained functions can do nonlocal gotos.  */
                   3671: 
1.1.1.2 ! root     3672:   /* For calls to `setjmp', etc., inform flow.c it should complain
        !          3673:      if nonvolatile values are live.  */
        !          3674: 
        !          3675:   if (is_setjmp)
        !          3676:     emit_note (IDENTIFIER_POINTER (DECL_NAME (fndecl)), NOTE_INSN_SETJMP);
        !          3677: 
        !          3678:   /* If size of args is variable, restore saved stack-pointer value.  */
        !          3679: 
        !          3680:   if (args_size.var != 0)
        !          3681:     {
        !          3682:       emit_move_insn (stack_pointer_rtx, old_stack_level);
        !          3683:       pending_stack_adjust = old_pending_adj;
        !          3684:     }
        !          3685: 
1.1       root     3686:   /* If value type not void, return an rtx for the value.  */
                   3687: 
1.1.1.2 ! root     3688:   if (TYPE_MODE (TREE_TYPE (exp)) == VOIDmode
        !          3689:       || ignore)
1.1       root     3690:     return 0;
                   3691: 
                   3692:   if (structure_value_addr)
                   3693:     {
                   3694:       if (target)
                   3695:        return target;
1.1.1.2 ! root     3696:       return gen_rtx (MEM, BLKmode,
        !          3697:                      memory_address (BLKmode, structure_value_addr));
1.1       root     3698:     }
1.1.1.2 ! root     3699: 
        !          3700:  if (target && GET_MODE (target) == TYPE_MODE (TREE_TYPE (exp)))
1.1       root     3701:     {
1.1.1.2 ! root     3702:       if (!rtx_equal_p (target, valreg))
        !          3703:        emit_move_insn (target, valreg);
        !          3704:       else
        !          3705:        /* This tells expand_inline_function to copy valreg to its target.  */
        !          3706:        emit_insn (gen_rtx (USE, VOIDmode, valreg));
1.1       root     3707:       return target;
                   3708:     }
1.1.1.2 ! root     3709:   return copy_to_reg (valreg);
1.1       root     3710: }
                   3711: 
                   3712: /* Expand conditional expressions.  */
                   3713: 
                   3714: /* Generate code to evaluate EXP and jump to LABEL if the value is zero.
                   3715:    LABEL is an rtx of code CODE_LABEL, in this function and all the
                   3716:    functions here.  */
                   3717: 
1.1.1.2 ! root     3718: void
1.1       root     3719: jumpifnot (exp, label)
                   3720:      tree exp;
                   3721:      rtx label;
                   3722: {
                   3723:   do_jump (exp, label, 0);
                   3724: }
                   3725: 
                   3726: /* Generate code to evaluate EXP and jump to LABEL if the value is nonzero.  */
                   3727: 
1.1.1.2 ! root     3728: void
1.1       root     3729: jumpif (exp, label)
                   3730:      tree exp;
                   3731:      rtx label;
                   3732: {
                   3733:   do_jump (exp, 0, label);
                   3734: }
                   3735: 
                   3736: /* Generate code to evaluate EXP and jump to IF_FALSE_LABEL if
                   3737:    the result is zero, or IF_TRUE_LABEL if the result is one.
                   3738:    Either of IF_FALSE_LABEL and IF_TRUE_LABEL may be zero,
                   3739:    meaning fall through in that case.
                   3740: 
                   3741:    This function is responsible for optimizing cases such as
                   3742:    &&, || and comparison operators in EXP.  */
                   3743: 
1.1.1.2 ! root     3744: void
1.1       root     3745: do_jump (exp, if_false_label, if_true_label)
                   3746:      tree exp;
                   3747:      rtx if_false_label, if_true_label;
                   3748: {
                   3749:   register enum tree_code code = TREE_CODE (exp);
                   3750:   /* Some cases need to create a label to jump to
                   3751:      in order to properly fall through.
                   3752:      These cases set DROP_THROUGH_LABEL nonzero.  */
                   3753:   rtx drop_through_label = 0;
                   3754:   rtx temp;
                   3755:   rtx comparison = 0;
                   3756: 
                   3757:   emit_queue ();
                   3758: 
                   3759:   switch (code)
                   3760:     {
                   3761:     case ERROR_MARK:
                   3762:       break;
                   3763: 
                   3764:     case INTEGER_CST:
                   3765:       temp = integer_zerop (exp) ? if_false_label : if_true_label;
                   3766:       if (temp)
                   3767:        emit_jump (temp);
                   3768:       break;
                   3769: 
                   3770:     case ADDR_EXPR:
                   3771:       /* The address of something can never be zero.  */
                   3772:       if (if_true_label)
                   3773:        emit_jump (if_true_label);
                   3774:       break;
1.1.1.2 ! root     3775:       
1.1       root     3776:     case NOP_EXPR:
                   3777:       do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
                   3778:       break;
                   3779: 
                   3780:     case TRUTH_NOT_EXPR:
                   3781:       do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label);
                   3782:       break;
                   3783: 
                   3784:     case TRUTH_ANDIF_EXPR:
                   3785:       if (if_false_label == 0)
                   3786:        if_false_label = drop_through_label = gen_label_rtx ();
                   3787:       do_jump (TREE_OPERAND (exp, 0), if_false_label, 0);
                   3788:       do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
                   3789:       break;
                   3790: 
                   3791:     case TRUTH_ORIF_EXPR:
                   3792:       if (if_true_label == 0)
                   3793:        if_true_label = drop_through_label = gen_label_rtx ();
                   3794:       do_jump (TREE_OPERAND (exp, 0), 0, if_true_label);
                   3795:       do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
                   3796:       break;
                   3797: 
                   3798:     case COMPOUND_EXPR:
1.1.1.2 ! root     3799:       expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0);
1.1       root     3800:       emit_queue ();
                   3801:       do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
                   3802:       break;
                   3803: 
                   3804:     case COND_EXPR:
                   3805:       {
                   3806:        register rtx label1 = gen_label_rtx ();
                   3807:        drop_through_label = gen_label_rtx ();
                   3808:        do_jump (TREE_OPERAND (exp, 0), label1, 0);
                   3809:        /* Now the THEN-expression.  */
                   3810:        do_jump (TREE_OPERAND (exp, 1),
                   3811:                 if_false_label ? if_false_label : drop_through_label,
                   3812:                 if_true_label ? if_true_label : drop_through_label);
                   3813:        emit_label (label1);
                   3814:        /* Now the ELSE-expression.  */
                   3815:        do_jump (TREE_OPERAND (exp, 2),
                   3816:                 if_false_label ? if_false_label : drop_through_label,
                   3817:                 if_true_label ? if_true_label : drop_through_label);
                   3818:       }
                   3819:       break;
                   3820: 
                   3821:     case EQ_EXPR:
                   3822:       comparison = compare (exp, EQ, EQ, EQ, EQ);
                   3823:       break;
                   3824: 
                   3825:     case NE_EXPR:
                   3826:       comparison = compare (exp, NE, NE, NE, NE);
                   3827:       break;
                   3828: 
                   3829:     case LT_EXPR:
                   3830:       comparison = compare (exp, LT, LTU, GT, GTU);
                   3831:       break;
                   3832: 
                   3833:     case LE_EXPR:
                   3834:       comparison = compare (exp, LE, LEU, GE, GEU);
                   3835:       break;
                   3836: 
                   3837:     case GT_EXPR:
                   3838:       comparison = compare (exp, GT, GTU, LT, LTU);
                   3839:       break;
                   3840: 
                   3841:     case GE_EXPR:
                   3842:       comparison = compare (exp, GE, GEU, LE, LEU);
                   3843:       break;
                   3844: 
                   3845:     default:
                   3846:       temp = expand_expr (exp, 0, VOIDmode, 0);
1.1.1.2 ! root     3847:       /* Copy to register to avoid generating bad insns by cse
        !          3848:         from (set (mem ...) (arithop))  (set (cc0) (mem ...)).  */
        !          3849:       if (!cse_not_expected && GET_CODE (temp) == MEM)
        !          3850:        temp = copy_to_reg (temp);
1.1       root     3851:       do_pending_stack_adjust ();
1.1.1.2 ! root     3852:       {
        !          3853:        rtx zero;
        !          3854:        if (GET_MODE (temp) == SFmode)
        !          3855:          zero = fconst0_rtx;
        !          3856:        else if (GET_MODE (temp) == DFmode)
        !          3857:          zero = dconst0_rtx;
        !          3858:        else
        !          3859:          zero = const0_rtx;
1.1       root     3860: 
1.1.1.2 ! root     3861:        if (GET_CODE (temp) == CONST_INT)
        !          3862:          comparison = compare_constants (NE, 0,
        !          3863:                                          INTVAL (temp), 0, BITS_PER_WORD);
        !          3864:        else if (GET_MODE (temp) != VOIDmode)
        !          3865:          comparison = compare1 (temp, zero, NE, NE, 0, GET_MODE (temp));
        !          3866:        else
        !          3867:          abort ();
        !          3868:       }
1.1       root     3869:     }
                   3870: 
1.1.1.2 ! root     3871:   /* Do any postincrements in the expression that was tested.  */
        !          3872:   emit_queue ();
        !          3873: 
1.1       root     3874:   /* If COMPARISON is nonzero here, it is an rtx that can be substituted
                   3875:      straight into a conditional jump instruction as the jump condition.
                   3876:      Otherwise, all the work has been done already.  */
                   3877: 
1.1.1.2 ! root     3878:   if (comparison == const1_rtx)
        !          3879:     {
        !          3880:       if (if_true_label)
        !          3881:        emit_jump (if_true_label);
        !          3882:     }
        !          3883:   else if (comparison == const0_rtx)
        !          3884:     {
        !          3885:       if (if_false_label)
        !          3886:        emit_jump (if_false_label);
        !          3887:     }
        !          3888:   else if (comparison)
        !          3889:     {
        !          3890:       if (if_true_label)
        !          3891:        {
        !          3892:          emit_jump_insn (gen_rtx (SET, VOIDmode, pc_rtx,
        !          3893:                                   gen_rtx (IF_THEN_ELSE, VOIDmode, comparison,
        !          3894:                                            gen_rtx (LABEL_REF, VOIDmode,
        !          3895:                                                     if_true_label),
        !          3896:                                            pc_rtx)));
        !          3897:          if (if_false_label)
        !          3898:            emit_jump (if_false_label);
        !          3899:        }
        !          3900:       else if (if_false_label)
        !          3901:        {
        !          3902:          emit_jump_insn (gen_rtx (SET, VOIDmode, pc_rtx,
        !          3903:                                   gen_rtx (IF_THEN_ELSE, VOIDmode, comparison,
        !          3904:                                            pc_rtx,
        !          3905:                                            gen_rtx (LABEL_REF, VOIDmode,
        !          3906:                                                     if_false_label))));
        !          3907:        }
        !          3908:     }
1.1       root     3909: 
                   3910:   if (drop_through_label)
                   3911:     emit_label (drop_through_label);
                   3912: }
                   3913: 
1.1.1.2 ! root     3914: /* Compare two integer constant rtx's, OP0 and OP1.
        !          3915:    The comparison operation is OPERATION.
        !          3916:    Return an rtx representing the value 1 or 0.
        !          3917:    WIDTH is the width in bits that is significant.  */
        !          3918: 
        !          3919: static rtx
        !          3920: compare_constants (operation, unsignedp, op0, op1, width)
        !          3921:      enum rtx_code operation;
        !          3922:      int unsignedp;
        !          3923:      int op0, op1;
        !          3924:      int width;
        !          3925: {
        !          3926:   int val;
        !          3927: 
        !          3928:   /* Sign-extend or zero-extend the operands to a full word
        !          3929:      from an initial width of WIDTH bits.  */
        !          3930:   if (width < HOST_BITS_PER_INT)
        !          3931:     {
        !          3932:       op0 &= (1 << width) - 1;
        !          3933:       op1 &= (1 << width) - 1;
        !          3934: 
        !          3935:       if (! unsignedp)
        !          3936:        {
        !          3937:          if (op0 & (1 << (width - 1)))
        !          3938:            op0 |= ((-1) << width);
        !          3939:          if (op1 & (1 << (width - 1)))
        !          3940:            op1 |= ((-1) << width);
        !          3941:        }
        !          3942:     }
        !          3943: 
        !          3944:   switch (operation)
        !          3945:     {
        !          3946:     case EQ:
        !          3947:       val = op0 == op1;
        !          3948:       break;
        !          3949: 
        !          3950:     case NE:
        !          3951:       val = op0 != op1;
        !          3952:       break;
        !          3953: 
        !          3954:     case GT:
        !          3955:     case GTU:
        !          3956:       val = op0 > op1;
        !          3957:       break;
        !          3958: 
        !          3959:     case LT:
        !          3960:     case LTU:
        !          3961:       val = op0 < op1;
        !          3962:       break;
        !          3963: 
        !          3964:     case GE:
        !          3965:     case GEU:
        !          3966:       val = op0 >= op1;
        !          3967:       break;
        !          3968: 
        !          3969:     case LE:
        !          3970:     case LEU:
        !          3971:       val = op0 <= op1;
        !          3972:     }
        !          3973: 
        !          3974:   return val ? const1_rtx : const0_rtx;
        !          3975: }
        !          3976: 
1.1       root     3977: /* Generate code for a comparison expression EXP
                   3978:    (including code to compute the values to be compared)
                   3979:    and set (CC0) according to the result.
                   3980:    SIGNED_FORWARD should be the rtx operation for this comparison for
                   3981:    signed data; UNSIGNED_FORWARD, likewise for use if data is unsigned.
                   3982:    SIGNED_REVERSE and UNSIGNED_REVERSE are used if it is desirable
                   3983:    to interchange the operands for the compare instruction.
                   3984: 
                   3985:    We force a stack adjustment unless there are currently
                   3986:    things pushed on the stack that aren't yet used.  */
                   3987: 
                   3988: static rtx
                   3989: compare (exp, signed_forward, unsigned_forward,
                   3990:         signed_reverse, unsigned_reverse)
                   3991:      register tree exp;
                   3992:      enum rtx_code signed_forward, unsigned_forward;
                   3993:      enum rtx_code signed_reverse, unsigned_reverse;
                   3994: {
1.1.1.2 ! root     3995: 
1.1       root     3996:   register rtx op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
                   3997:   register rtx op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
                   3998:   register enum machine_mode mode = GET_MODE (op0);
                   3999:   int unsignedp;
                   4000: 
                   4001:   /* If one operand is 0, make it the second one.  */
                   4002: 
                   4003:   if (op0 == const0_rtx || op0 == fconst0_rtx || op0 == dconst0_rtx)
                   4004:     {
                   4005:       rtx tem = op0;
                   4006:       op0 = op1;
                   4007:       op1 = tem;
                   4008:       signed_forward = signed_reverse;
                   4009:       unsigned_forward = unsigned_reverse;
                   4010:     }
                   4011: 
1.1.1.2 ! root     4012:   if (flag_force_mem)
1.1       root     4013:     {
                   4014:       op0 = force_not_mem (op0);
                   4015:       op1 = force_not_mem (op1);
                   4016:     }
                   4017: 
                   4018:   do_pending_stack_adjust ();
                   4019: 
1.1.1.2 ! root     4020:   unsignedp = (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0)))
        !          4021:               || TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 1))));
        !          4022: 
        !          4023:   if (GET_CODE (op0) == CONST_INT && GET_CODE (op1) == CONST_INT)
        !          4024:     return compare_constants (signed_forward, unsignedp,
        !          4025:                              INTVAL (op0), INTVAL (op1),
        !          4026:                              GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))));
1.1       root     4027: 
                   4028:   emit_cmp_insn (op0, op1,
                   4029:                 (mode == BLKmode) ? expr_size (TREE_OPERAND (exp, 0)) : 0,
                   4030:                 unsignedp);
                   4031: 
                   4032:   return gen_rtx ((unsignedp ? unsigned_forward : signed_forward),
                   4033:                  VOIDmode, cc0_rtx, const0_rtx);
                   4034: }
                   4035: 
                   4036: /* Like compare but expects the values to compare as two rtx's.
                   4037:    The decision as to signed or unsigned comparison must be made by the caller.
                   4038:    BLKmode is not allowed.  */
                   4039: 
                   4040: static rtx
1.1.1.2 ! root     4041: compare1 (op0, op1, forward_op, reverse_op, unsignedp, mode)
1.1       root     4042:      register rtx op0, op1;
                   4043:      enum rtx_code forward_op, reverse_op;
                   4044:      int unsignedp;
1.1.1.2 ! root     4045:      enum machine_mode mode;
1.1       root     4046: {
                   4047:   /* If one operand is 0, make it the second one.  */
                   4048: 
                   4049:   if (op0 == const0_rtx || op0 == fconst0_rtx || op0 == dconst0_rtx)
                   4050:     {
                   4051:       rtx tem = op0;
                   4052:       op0 = op1;
                   4053:       op1 = tem;
                   4054:       forward_op = reverse_op;
                   4055:     }
                   4056: 
1.1.1.2 ! root     4057:   if (flag_force_mem)
1.1       root     4058:     {
                   4059:       op0 = force_not_mem (op0);
                   4060:       op1 = force_not_mem (op1);
                   4061:     }
                   4062: 
                   4063:   do_pending_stack_adjust ();
                   4064: 
1.1.1.2 ! root     4065:   if (GET_CODE (op0) == CONST_INT && GET_CODE (op1) == CONST_INT)
        !          4066:     return compare_constants (forward_op, unsignedp,
        !          4067:                              INTVAL (op0), INTVAL (op1),
        !          4068:                              GET_MODE_BITSIZE (mode));
        !          4069: 
1.1       root     4070:   emit_cmp_insn (op0, op1, 0, unsignedp);
                   4071: 
                   4072:   return gen_rtx (forward_op, VOIDmode, cc0_rtx, const0_rtx);
                   4073: }
                   4074: 
                   4075: /* Generate code to calculate EXP using a store-flag instruction
                   4076:    and return an rtx for the result.
                   4077:    If TARGET is nonzero, store the result there if convenient.
                   4078: 
                   4079:    Return zero if there is no suitable set-flag instruction
                   4080:    available on this machine.  */
                   4081: 
                   4082: static rtx
1.1.1.2 ! root     4083: do_store_flag (exp, target, mode)
1.1       root     4084:      tree exp;
                   4085:      rtx target;
1.1.1.2 ! root     4086:      enum machine_mode mode;
1.1       root     4087: {
                   4088:   register enum tree_code code = TREE_CODE (exp);
                   4089:   register rtx comparison = 0;
1.1.1.2 ! root     4090:   enum machine_mode compare_mode;
1.1       root     4091: 
                   4092:   switch (code)
                   4093:     {
1.1.1.2 ! root     4094: #ifdef HAVE_seq
1.1       root     4095:     case EQ_EXPR:
1.1.1.2 ! root     4096:       if (HAVE_seq)
        !          4097:        {
        !          4098:          comparison = compare (exp, EQ, EQ, EQ, EQ);
        !          4099:          compare_mode = insn_operand_mode[(int) CODE_FOR_seq][0];
        !          4100:        }
1.1       root     4101:       break;
                   4102: #endif
                   4103: 
1.1.1.2 ! root     4104: #ifdef HAVE_sne
1.1       root     4105:     case NE_EXPR:
1.1.1.2 ! root     4106:       if (HAVE_sne)
        !          4107:        {
        !          4108:          comparison = compare (exp, NE, NE, NE, NE);
        !          4109:          compare_mode = insn_operand_mode[(int) CODE_FOR_sne][0];
        !          4110:        }
1.1       root     4111:       break;
                   4112: #endif
                   4113: 
1.1.1.2 ! root     4114: #if defined (HAVE_slt) && defined (HAVE_sltu) && defined (HAVE_sgt) && defined (HAVE_sgtu)
1.1       root     4115:     case LT_EXPR:
1.1.1.2 ! root     4116:       if (HAVE_slt && HAVE_sltu && HAVE_sgt && HAVE_sgtu)
        !          4117:        {
        !          4118:          comparison = compare (exp, LT, LTU, GT, GTU);
        !          4119:          compare_mode = insn_operand_mode[(int) CODE_FOR_slt][0];
        !          4120:        }
1.1       root     4121:       break;
                   4122: 
                   4123:     case GT_EXPR:
1.1.1.2 ! root     4124:       if (HAVE_slt && HAVE_sltu && HAVE_sgt && HAVE_sgtu)
        !          4125:        {
        !          4126:          comparison = compare (exp, GT, GTU, LT, LTU);
        !          4127:          compare_mode = insn_operand_mode[(int) CODE_FOR_slt][0];
        !          4128:        }
1.1       root     4129:       break;
                   4130: #endif
                   4131: 
1.1.1.2 ! root     4132: #if defined (HAVE_sle) && defined (HAVE_sleu) && defined (HAVE_sge) && defined (HAVE_sgeu)
1.1       root     4133:     case LE_EXPR:
1.1.1.2 ! root     4134:       if (HAVE_sle && HAVE_sleu && HAVE_sge && HAVE_sgeu)
        !          4135:        {
        !          4136:          comparison = compare (exp, LE, LEU, GE, GEU);
        !          4137:          compare_mode = insn_operand_mode[(int) CODE_FOR_sle][0];
        !          4138:        }
1.1       root     4139:       break;
                   4140: 
                   4141:     case GE_EXPR:
1.1.1.2 ! root     4142:       if (HAVE_sle && HAVE_sleu && HAVE_sge && HAVE_sgeu)
        !          4143:        {
        !          4144:          comparison = compare (exp, GE, GEU, LE, LEU);
        !          4145:          compare_mode = insn_operand_mode[(int) CODE_FOR_sle][0];
        !          4146:        }
1.1       root     4147:       break;
                   4148: #endif
                   4149:     }
                   4150:   if (comparison == 0)
                   4151:     return 0;
                   4152: 
1.1.1.2 ! root     4153:   if (target == 0 || GET_MODE (target) != mode
        !          4154:       || (mode != compare_mode && GET_CODE (target) != REG))
        !          4155:     target = gen_reg_rtx (mode);
        !          4156: 
        !          4157:   /* Store the comparison in its proper mode.  */
        !          4158:   if (GET_MODE (target) != compare_mode)
        !          4159:     emit_insn (gen_rtx (SET, VOIDmode,
        !          4160:                        gen_rtx (SUBREG, compare_mode, target, 0),
        !          4161:                        comparison));
        !          4162:   else
        !          4163:     emit_insn (gen_rtx (SET, VOIDmode, target, comparison));
        !          4164: 
        !          4165: #if STORE_FLAG_VALUE != 1
        !          4166:   expand_bit_and (mode, target, const1_rtx, target);
        !          4167: #endif
1.1       root     4168:   return target;
                   4169: }
                   4170: 
                   4171: /* Generate a tablejump instruction (used for switch statements).  */
                   4172: 
                   4173: #ifdef HAVE_tablejump
                   4174: 
                   4175: /* INDEX is the value being switched on, with the lowest value
                   4176:    in the table already subtracted.
                   4177:    RANGE is the length of the jump table.
                   4178:    TABLE_LABEL is a CODE_LABEL rtx for the table itself.
1.1.1.2 ! root     4179: 
1.1       root     4180:    DEFAULT_LABEL is a CODE_LABEL rtx to jump to if the
                   4181:    index value is out of range.  */
                   4182: 
                   4183: void
                   4184: do_tablejump (index, range, table_label, default_label)
                   4185:      rtx index, range, table_label, default_label;
                   4186: {
                   4187:   register rtx temp;
                   4188: 
                   4189:   emit_cmp_insn (range, index, 0);
1.1.1.2 ! root     4190:   emit_jump_insn (gen_bltu (default_label));
1.1       root     4191:   index = memory_address (CASE_VECTOR_MODE,
                   4192:                          gen_rtx (PLUS, Pmode,
                   4193:                                   gen_rtx (MULT, Pmode, index,
                   4194:                                            gen_rtx (CONST_INT, VOIDmode,
1.1.1.2 ! root     4195:                                                     GET_MODE_SIZE (CASE_VECTOR_MODE))),
        !          4196:                                   gen_rtx (LABEL_REF, VOIDmode, table_label)));
1.1       root     4197:   temp = gen_reg_rtx (CASE_VECTOR_MODE);
                   4198:   convert_move (temp, gen_rtx (MEM, CASE_VECTOR_MODE, index), 0);
                   4199: 
1.1.1.2 ! root     4200:   emit_jump_insn (gen_tablejump (temp, table_label));
1.1       root     4201: }
                   4202: 
1.1.1.2 ! root     4203: #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.