Annotation of gcc/expr.c, revision 1.1.1.6

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

unix.superglobalmegacorp.com

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