Annotation of researchv10dc/cmd/gcc/expmed.c, revision 1.1

1.1     ! root        1: /* Medium-level subroutines: convert bit-field store and extract
        !             2:    and shifts, multiplies and divides to rtl instructions.
        !             3:    Copyright (C) 1987, 1988 Free Software Foundation, Inc.
        !             4: 
        !             5: This file is part of GNU CC.
        !             6: 
        !             7: GNU CC is distributed in the hope that it will be useful,
        !             8: but WITHOUT ANY WARRANTY.  No author or distributor
        !             9: accepts responsibility to anyone for the consequences of using it
        !            10: or for whether it serves any particular purpose or works at all,
        !            11: unless he says so in writing.  Refer to the GNU CC General Public
        !            12: License for full details.
        !            13: 
        !            14: Everyone is granted permission to copy, modify and redistribute
        !            15: GNU CC, but only under the conditions described in the
        !            16: GNU CC General Public License.   A copy of this license is
        !            17: supposed to have been given to you along with GNU CC so you
        !            18: can know your rights and responsibilities.  It should be in a
        !            19: file named COPYING.  Among other things, the copyright notice
        !            20: and this notice must be preserved on all copies.  */
        !            21: 
        !            22: 
        !            23: #include "config.h"
        !            24: #include "rtl.h"
        !            25: #include "tree.h"
        !            26: #include "flags.h"
        !            27: #include "insn-flags.h"
        !            28: #include "insn-codes.h"
        !            29: #include "insn-config.h"
        !            30: #include "expr.h"
        !            31: #include "recog.h"
        !            32: 
        !            33: static rtx extract_split_bit_field ();
        !            34: static rtx extract_fixed_bit_field ();
        !            35: static void store_split_bit_field ();
        !            36: static void store_fixed_bit_field ();
        !            37: 
        !            38: /* Return an rtx representing minus the value of X.  */
        !            39: 
        !            40: rtx
        !            41: negate_rtx (x)
        !            42:      rtx x;
        !            43: {
        !            44:   if (GET_CODE (x) == CONST_INT)
        !            45:     return gen_rtx (CONST_INT, VOIDmode, - INTVAL (x));
        !            46:   else
        !            47:     return expand_unop (GET_MODE (x), neg_optab, x, 0, 0);
        !            48: }
        !            49: 
        !            50: /* Generate code to store value from rtx VALUE
        !            51:    into a bit-field within structure STR_RTX
        !            52:    containing BITSIZE bits starting at bit BITNUM.
        !            53:    FIELDMODE is the machine-mode of the FIELD_DECL node for this field.  */
        !            54: 
        !            55: /* ??? This should really have the ability to copy a word into a register
        !            56:    in order to store the bit-field into it, on machines whose insv insns
        !            57:    work that way.  */
        !            58: 
        !            59: rtx
        !            60: store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value)
        !            61:      rtx str_rtx;
        !            62:      register int bitsize;
        !            63:      int bitnum;
        !            64:      enum machine_mode fieldmode;
        !            65:      rtx value;
        !            66: {
        !            67:   int unit = (GET_CODE (str_rtx) == MEM) ? BITS_PER_UNIT : BITS_PER_WORD;
        !            68:   register int offset = bitnum / unit;
        !            69:   register int bitpos = bitnum % unit;
        !            70:   register rtx op0 = str_rtx;
        !            71:   rtx value1;
        !            72: 
        !            73:   if (GET_CODE (op0) == SUBREG)
        !            74:     {
        !            75:       offset += SUBREG_WORD (op0);
        !            76:       op0 = SUBREG_REG (op0);
        !            77:     }
        !            78: 
        !            79:   value = protect_from_queue (value, 0);
        !            80: 
        !            81:   if (flag_force_mem)
        !            82:     value = force_not_mem (value);
        !            83: 
        !            84:   if (GET_MODE_SIZE (fieldmode) >= UNITS_PER_WORD)
        !            85:     {
        !            86:       /* Storing in a full-word or multi-word field in a register
        !            87:         can be done with just SUBREG.  */
        !            88:       if (GET_MODE (op0) != fieldmode)
        !            89:        op0 = gen_rtx (SUBREG, fieldmode, op0, offset);
        !            90:       emit_move_insn (op0, value);
        !            91:       return value;
        !            92:     }
        !            93: 
        !            94: #ifdef BYTES_BIG_ENDIAN
        !            95:   /* If OP0 is a register, BITPOS must count within a word.
        !            96:      But as we have it, it counts within whatever size OP0 now has.
        !            97:      On a bigendian machine, these are not the same, so convert.  */
        !            98:   if (GET_CODE (op0) != MEM && unit > GET_MODE_BITSIZE (GET_MODE (op0)))
        !            99:     bitpos += unit - GET_MODE_BITSIZE (GET_MODE (op0));
        !           100: #endif
        !           101: 
        !           102:   /* Storing an lsb-aligned field in a register
        !           103:      can be done with a movestrict instruction.  */
        !           104: 
        !           105:   if (GET_CODE (op0) != MEM
        !           106: #ifdef BYTES_BIG_ENDIAN
        !           107:       && bitpos + bitsize == unit
        !           108: #else
        !           109:       && bitpos == 0
        !           110: #endif
        !           111:       && (GET_MODE (op0) == fieldmode
        !           112:          || (movstrict_optab->handlers[(int) fieldmode].insn_code
        !           113:              != CODE_FOR_nothing)))
        !           114:     {
        !           115:       /* Get appropriate low part of the value being stored.  */
        !           116:       if (GET_CODE (value) == CONST_INT || GET_CODE (value) == REG)
        !           117:        value = gen_lowpart (fieldmode, value);
        !           118:       else if (!(GET_CODE (value) == SYMBOL_REF
        !           119:                 || GET_CODE (value) == LABEL_REF
        !           120:                 || GET_CODE (value) == CONST))
        !           121:        value = convert_to_mode (fieldmode, value, 0);
        !           122: 
        !           123:       if (GET_MODE (op0) == fieldmode)
        !           124:        emit_move_insn (op0, value);
        !           125:       else
        !           126:        emit_insn (GEN_FCN (movstrict_optab->handlers[(int) fieldmode].insn_code)
        !           127:                   (gen_rtx (SUBREG, fieldmode, op0, offset), value));
        !           128: 
        !           129:       return value;
        !           130:     }
        !           131: 
        !           132:   /* From here on we can assume that the field to be stored in is an integer,
        !           133:      since it is shorter than a word.  */
        !           134: 
        !           135:   /* OFFSET is the number of words or bytes (UNIT says which)
        !           136:      from STR_RTX to the first word or byte containing part of the field.  */
        !           137: 
        !           138:   if (GET_CODE (op0) == REG)
        !           139:     {
        !           140:       if (offset != 0
        !           141:          || GET_MODE_SIZE (GET_MODE (op0)) > GET_MODE_SIZE (SImode))
        !           142:        op0 = gen_rtx (SUBREG, SImode, op0, offset);
        !           143:       offset = 0;
        !           144:     }
        !           145:   else
        !           146:     {
        !           147:       op0 = protect_from_queue (op0, 1);
        !           148:     }
        !           149: 
        !           150:   /* Now OFFSET is nonzero only if OP0 is memory
        !           151:      and is therefore always measured in bytes.  */
        !           152: 
        !           153: #ifdef HAVE_insv
        !           154:   if (HAVE_insv
        !           155:       && !(bitsize == 1 && GET_CODE (value) == CONST_INT))
        !           156:     {
        !           157:       enum machine_mode mode0 = GET_MODE (op0);
        !           158: 
        !           159:       /* Add OFFSET into OP0's address.  */
        !           160:       if (GET_CODE (op0) == MEM)
        !           161:        op0 = change_address (op0, QImode,
        !           162:                              plus_constant (XEXP (op0, 0), offset));
        !           163: 
        !           164:       /* If op0 is a register, we need it in SImode
        !           165:         to make it acceptable to the format of insv.  */
        !           166:       if (GET_CODE (op0) == SUBREG)
        !           167:        PUT_MODE (op0, SImode);
        !           168:       if (GET_CODE (op0) == REG && GET_MODE (op0) != SImode)
        !           169:        op0 = gen_rtx (SUBREG, SImode, op0, 0);
        !           170: 
        !           171:       /* Convert VALUE to SImode (which insv insn wants) in VALUE1.  */
        !           172:       value1 = value;
        !           173:       if (GET_MODE (value) != SImode)
        !           174:        {
        !           175:          if (GET_MODE_BITSIZE (GET_MODE (value)) >= bitsize)
        !           176:            {
        !           177:              if (GET_CODE (value) != REG)
        !           178:                value1 = copy_to_reg (value);
        !           179:              /* Optimization: Don't bother really extending VALUE
        !           180:                 if it has all the bits we will actually use.  */
        !           181:              value1 = gen_rtx (SUBREG, SImode, value1, 0);
        !           182:            }
        !           183:          else if (!CONSTANT_P (value))
        !           184:            /* Parse phase is supposed to make VALUE's data type
        !           185:               match that of the component reference, which is a type
        !           186:               at least as wide as the field; so VALUE should have
        !           187:               a mode that corresponds to that type.  */
        !           188:            abort ();
        !           189:        }
        !           190: 
        !           191:       /* If this machine's insv insists on a register,
        !           192:         get VALUE1 into a register.  */
        !           193:       if (! (*insn_operand_predicate[(int) CODE_FOR_insv][3]) (value1, SImode))
        !           194:        value1 = force_reg (SImode, value1);
        !           195: 
        !           196:       /* On big-endian machines, we count bits from the most significant.
        !           197:         If the bit field insn does not, we must invert.  */
        !           198: 
        !           199: #if defined (BITS_BIG_ENDIAN) != defined (BYTES_BIG_ENDIAN)
        !           200:       bitpos = unit - 1 - bitpos;
        !           201: #endif
        !           202: 
        !           203:       emit_insn (gen_insv (op0,
        !           204:                           gen_rtx (CONST_INT, VOIDmode, bitsize),
        !           205:                           gen_rtx (CONST_INT, VOIDmode, bitpos),
        !           206:                           value1));
        !           207:     }
        !           208:   else
        !           209: #endif
        !           210:     /* Insv is not available; store using shifts and boolean ops.  */
        !           211:     store_fixed_bit_field (op0, offset, bitsize, bitpos, value);
        !           212:   return value;
        !           213: }
        !           214: 
        !           215: /* Use shifts and boolean operations to store VALUE
        !           216:    into a bit field of width BITSIZE
        !           217:    in a memory location specified by OP0 except offset by OFFSET bytes.
        !           218:    The field starts at position BITPOS within the byte.
        !           219:     (If OP0 is a register, it may be SImode or a narrower mode,
        !           220:      but BITPOS still counts within a full word,
        !           221:      which is significant on bigendian machines.)
        !           222: 
        !           223:    Note that protect_from_queue has already been done on OP0 and VALUE.  */
        !           224: 
        !           225: static void
        !           226: store_fixed_bit_field (op0, offset, bitsize, bitpos, value)
        !           227:      register rtx op0;
        !           228:      register int offset, bitsize, bitpos;
        !           229:      register rtx value;
        !           230: {
        !           231:   register enum machine_mode mode;
        !           232:   int total_bits = BITS_PER_WORD;
        !           233:   rtx subtarget;
        !           234:   int all_zero = 0;
        !           235:   int all_one = 0;
        !           236: 
        !           237:   /* Add OFFSET to OP0's address (if it is in memory)
        !           238:      and if a single byte contains the whole bit field
        !           239:      change OP0 to a byte.  */
        !           240: 
        !           241:   if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG)
        !           242:     {
        !           243:       /* Special treatment for a bit field split across two registers.  */
        !           244:       if (bitsize + bitpos > BITS_PER_WORD)
        !           245:        {
        !           246:          store_split_bit_field (op0, bitsize, bitpos, value);
        !           247:          return;
        !           248:        }
        !           249:     }
        !           250:   else if (bitsize + bitpos <= BITS_PER_UNIT
        !           251:           && ! SLOW_BYTE_ACCESS)
        !           252:     {
        !           253:       total_bits = BITS_PER_UNIT;
        !           254:       op0 = change_address (op0, QImode, 
        !           255:                            plus_constant (XEXP (op0, 0), offset));
        !           256:     }
        !           257:   else
        !           258:     {
        !           259:       /* Get ref to word containing the field.  */
        !           260:       /* Adjust BITPOS to be position within a word,
        !           261:         and OFFSET to be the offset of that word.
        !           262:         Then alter OP0 to refer to that word.  */
        !           263:       bitpos += (offset % (BITS_PER_WORD / BITS_PER_UNIT)) * BITS_PER_UNIT;
        !           264:       offset -= (offset % (BITS_PER_WORD / BITS_PER_UNIT));
        !           265:       op0 = change_address (op0, SImode,
        !           266:                            plus_constant (XEXP (op0, 0), offset));
        !           267:       /* Special treatment for a bit field split across two words.  */
        !           268:       if (bitsize + bitpos > BITS_PER_WORD)
        !           269:        {
        !           270:          store_split_bit_field (op0, bitsize, bitpos, value);
        !           271:          return;
        !           272:        }
        !           273:     }
        !           274: 
        !           275:   mode = GET_MODE (op0);
        !           276: 
        !           277:   /* Now OP0 is either a byte or a word, and the bit field is contained
        !           278:      entirely within it.  TOTAL_BITS and MODE say which one (byte or word).
        !           279:      BITPOS is the starting bit number within the byte or word.
        !           280:      (If OP0 is a word, it may actually have a mode narrower than SImode.)  */
        !           281: 
        !           282: #ifdef BYTES_BIG_ENDIAN
        !           283:   /* BITPOS is the distance between our msb
        !           284:      and that of the containing byte or word.
        !           285:      Convert it to the distance from the lsb.  */
        !           286: 
        !           287:   bitpos = total_bits - bitsize - bitpos;
        !           288: #endif
        !           289:   /* Now BITPOS is always the distance between our lsb
        !           290:      and that of the containing byte or word.  */
        !           291: 
        !           292:   /* Shift VALUE left by BITPOS bits.  If VALUE is not constant,
        !           293:      we must first convert its mode to MODE.  */
        !           294: 
        !           295:   if (GET_CODE (value) == CONST_INT)
        !           296:     {
        !           297:       register int v = INTVAL (value);
        !           298: 
        !           299:       if (bitsize < HOST_BITS_PER_INT)
        !           300:        v &= (1 << bitsize) - 1;
        !           301: 
        !           302:       if (v == 0)
        !           303:        all_zero = 1;
        !           304:       else if (bitsize < HOST_BITS_PER_INT && v == (1 << bitsize) - 1)
        !           305:        all_one = 1;
        !           306: 
        !           307:       value = gen_rtx (CONST_INT, VOIDmode, v << bitpos);
        !           308:     }
        !           309:   else
        !           310:     {
        !           311:       int must_and = (GET_MODE_BITSIZE (GET_MODE (value)) != bitsize);
        !           312: 
        !           313:       if (GET_MODE (value) != mode)
        !           314:        {
        !           315:          if (GET_CODE (value) == REG && mode == QImode)
        !           316:            value = gen_rtx (SUBREG, mode, value, 0);
        !           317:          else
        !           318:            value = convert_to_mode (mode, value, 1);
        !           319:        }
        !           320: 
        !           321:       if (must_and && bitsize < HOST_BITS_PER_INT)
        !           322:        value = expand_bit_and (mode, value,
        !           323:                                gen_rtx (CONST_INT, VOIDmode,
        !           324:                                         (1 << bitsize) - 1),
        !           325:                                0);
        !           326:       if (bitpos > 0)
        !           327:        value = expand_shift (LSHIFT_EXPR, mode, value,
        !           328:                              build_int_2 (bitpos, 0), 0, 1);
        !           329:     }
        !           330: 
        !           331:   /* Now clear the chosen bits in OP0,
        !           332:      except that if VALUE is -1 we need not bother.  */
        !           333: 
        !           334:   subtarget = op0;
        !           335: 
        !           336:   if (! all_one)
        !           337:     subtarget = expand_bit_and (mode, op0,
        !           338:                                gen_rtx (CONST_INT, VOIDmode, 
        !           339:                                         (~ (((1 << bitsize) - 1) << bitpos))
        !           340:                                          & ((1 << GET_MODE_BITSIZE (mode)) - 1)),
        !           341:                                subtarget);
        !           342: 
        !           343:   /* Now logical-or VALUE into OP0, unless it is zero.  */
        !           344: 
        !           345:   if (! all_zero)
        !           346:     subtarget = expand_binop (mode, ior_optab, subtarget, value,
        !           347:                              op0, 1, OPTAB_LIB_WIDEN);
        !           348:   if (op0 != subtarget)
        !           349:     emit_move_insn (op0, subtarget);
        !           350: }
        !           351: 
        !           352: /* Store a bit field that is split across two words.
        !           353: 
        !           354:    OP0 is the REG, SUBREG or MEM rtx for the first of the two words.
        !           355:    BITSIZE is the field width; BITPOS the position of its first bit
        !           356:    (within the word).
        !           357:    VALUE is the value to store.  */
        !           358: 
        !           359: static void
        !           360: store_split_bit_field (op0, bitsize, bitpos, value)
        !           361:      rtx op0;
        !           362:      int bitsize, bitpos;
        !           363:      rtx value;
        !           364: {
        !           365:   /* BITSIZE_1 is size of the part in the first word.  */
        !           366:   int bitsize_1 = BITS_PER_WORD - bitpos;
        !           367:   /* BITSIZE_2 is size of the rest (in the following word).  */
        !           368:   int bitsize_2 = bitsize - bitsize_1;
        !           369:   rtx part1, part2;
        !           370: 
        !           371:   if (GET_MODE (value) != VOIDmode)
        !           372:     value = convert_to_mode (SImode, value, 1);
        !           373:   if (CONSTANT_P (value) && GET_CODE (value) != CONST_INT)
        !           374:     value = copy_to_reg (value);
        !           375: 
        !           376:   /* Split the value into two parts:
        !           377:      PART1 gets that which goes in the first word; PART2 the other.  */
        !           378: #ifdef BYTES_BIG_ENDIAN
        !           379:   /* PART1 gets the more significant part.  */
        !           380:   if (GET_CODE (value) == CONST_INT)
        !           381:     {
        !           382:       part1 = gen_rtx (CONST_INT, VOIDmode,
        !           383:                       (unsigned) (INTVAL (value)) >> bitsize_2);
        !           384:       part2 = gen_rtx (CONST_INT, VOIDmode,
        !           385:                       (unsigned) (INTVAL (value)) & ((1 << bitsize_2) - 1));
        !           386:     }
        !           387:   else
        !           388:     {
        !           389:       part1 = extract_fixed_bit_field (SImode, value, 0, bitsize_1,
        !           390:                                       BITS_PER_WORD - bitsize, 0, 1);
        !           391:       part2 = extract_fixed_bit_field (SImode, value, 0, bitsize_2,
        !           392:                                       BITS_PER_WORD - bitsize_2, 0, 1);
        !           393:     }
        !           394: #else
        !           395:   /* PART1 gets the less significant part.  */
        !           396:   if (GET_CODE (value) == CONST_INT)
        !           397:     {
        !           398:       part1 = gen_rtx (CONST_INT, VOIDmode,
        !           399:                       (unsigned) (INTVAL (value)) & ((1 << bitsize_1) - 1));
        !           400:       part2 = gen_rtx (CONST_INT, VOIDmode,
        !           401:                       (unsigned) (INTVAL (value)) >> bitsize_1);
        !           402:     }
        !           403:   else
        !           404:     {
        !           405:       part1 = extract_fixed_bit_field (SImode, value, 0, bitsize_1, 0, 0, 1);
        !           406:       part2 = extract_fixed_bit_field (SImode, value, 0, bitsize_2,
        !           407:                                       bitsize_1, 0, 1);
        !           408:     }
        !           409: #endif
        !           410: 
        !           411:   /* Store PART1 into the first word.  */
        !           412:   store_fixed_bit_field (op0, 0, bitsize_1, bitpos, part1);
        !           413: 
        !           414:   /* Offset op0 to get to the following word.  */
        !           415:   if (GET_CODE (op0) == MEM)
        !           416:     op0 = change_address (op0, SImode,
        !           417:                          plus_constant (XEXP (op0, 0), UNITS_PER_WORD));
        !           418:   else if (GET_CODE (op0) == REG)
        !           419:     op0 = gen_rtx (SUBREG, SImode, op0, 1);
        !           420:   else
        !           421:     op0 = gen_rtx (SUBREG, SImode, SUBREG_REG (op0), SUBREG_WORD (op0) + 1);
        !           422: 
        !           423:   /* Store PART2 into the second word.  */
        !           424:   store_fixed_bit_field (op0, 0, bitsize_2, 0, part2);
        !           425: }
        !           426: 
        !           427: /* Generate code to extract a byte-field from STR_RTX
        !           428:    containing BITSIZE bits, starting at BITNUM,
        !           429:    and put it in TARGET if possible (if TARGET is nonzero).
        !           430:    Regardless of TARGET, we return the rtx for where the value is placed.
        !           431:    It may be a QUEUED.
        !           432: 
        !           433:    STR_RTX is the structure containing the byte (a REG or MEM).
        !           434:    UNSIGNEDP is nonzero if this is an unsigned bit field.
        !           435:    MODE is the natural mode of the field value once extracted.
        !           436:    TMODE is the mode the caller would like the value to have;
        !           437:    but the value may be returned with type MODE instead.
        !           438: 
        !           439:    If a TARGET is specified and we can store in it at no extra cost,
        !           440:    we do so, and return TARGET.
        !           441:    Otherwise, we return a REG of mode TMODE or MODE, with TMODE preferred
        !           442:    if they are equally easy.  */
        !           443: 
        !           444: rtx
        !           445: extract_bit_field (str_rtx, bitsize, bitnum, unsignedp, target, mode, tmode)
        !           446:      rtx str_rtx;
        !           447:      register int bitsize;
        !           448:      int bitnum;
        !           449:      int unsignedp;
        !           450:      rtx target;
        !           451:      enum machine_mode mode, tmode;
        !           452: {
        !           453:   int unit = (GET_CODE (str_rtx) == MEM) ? BITS_PER_UNIT : BITS_PER_WORD;
        !           454:   register int offset = bitnum / unit;
        !           455:   register int bitpos = bitnum % unit;
        !           456:   register rtx op0 = str_rtx;
        !           457:   rtx spec_target = target;
        !           458:   rtx bitsize_rtx, bitpos_rtx;
        !           459:   rtx spec_target_subreg = 0;
        !           460: 
        !           461:   if (tmode == VOIDmode)
        !           462:     tmode = mode;
        !           463: 
        !           464:   while (GET_CODE (op0) == SUBREG)
        !           465:     {
        !           466:       offset += SUBREG_WORD (op0);
        !           467:       op0 = SUBREG_REG (op0);
        !           468:     }
        !           469:   
        !           470: #ifdef BYTES_BIG_ENDIAN
        !           471:   /* If OP0 is a register, BITPOS must count within a word.
        !           472:      But as we have it, it counts within whatever size OP0 now has.
        !           473:      On a bigendian machine, these are not the same, so convert.  */
        !           474:   if (GET_CODE (op0) != MEM && unit > GET_MODE_BITSIZE (GET_MODE (op0)))
        !           475:     bitpos += unit - GET_MODE_BITSIZE (GET_MODE (op0));
        !           476: #endif
        !           477: 
        !           478:   /* Extracting a full-word or multi-word value
        !           479:      from a structure in a register.
        !           480:      This can be done with just SUBREG.
        !           481:      So too extracting a subword value in
        !           482:      the least significant part of the register.  */
        !           483: 
        !           484:   if (GET_CODE (op0) == REG
        !           485:       && (bitsize >= BITS_PER_WORD
        !           486:          || ((bitsize == GET_MODE_BITSIZE (mode)
        !           487:               || bitsize == GET_MODE_BITSIZE (QImode)
        !           488:               || bitsize == GET_MODE_BITSIZE (HImode))
        !           489: #ifdef BYTES_BIG_ENDIAN
        !           490:              && bitpos + bitsize == BITS_PER_WORD
        !           491: #else
        !           492:              && bitpos == 0
        !           493: #endif
        !           494:              )))
        !           495:     {
        !           496:       enum machine_mode mode1 = mode;
        !           497: 
        !           498:       if (bitsize == GET_MODE_BITSIZE (QImode))
        !           499:        mode1 = QImode;
        !           500:       if (bitsize == GET_MODE_BITSIZE (HImode))
        !           501:        mode1 = HImode;
        !           502: 
        !           503:       if (mode1 != GET_MODE (op0))
        !           504:        op0 = gen_rtx (SUBREG, mode1, op0, offset);
        !           505: 
        !           506:       if (mode1 != mode)
        !           507:        return convert_to_mode (tmode, op0, unsignedp);
        !           508:       return op0;
        !           509:     }
        !           510:   
        !           511:   /* From here on we know the desired field is smaller than a word
        !           512:      so we can assume it is an integer.  So we can safely extract it as one
        !           513:      size of integer, if necessary, and then truncate or extend
        !           514:      to the size that is wanted.  */
        !           515: 
        !           516:   /* OFFSET is the number of words or bytes (UNIT says which)
        !           517:      from STR_RTX to the first word or byte containing part of the field.  */
        !           518: 
        !           519:   if (GET_CODE (op0) == REG)
        !           520:     {
        !           521:       if (offset != 0
        !           522:          || GET_MODE_SIZE (GET_MODE (op0)) > GET_MODE_SIZE (SImode))
        !           523:        op0 = gen_rtx (SUBREG, SImode, op0, offset);
        !           524:       offset = 0;
        !           525:     }
        !           526:   else
        !           527:     {
        !           528:       op0 = protect_from_queue (str_rtx, 1);
        !           529:     }
        !           530: 
        !           531:   /* Now OFFSET is nonzero only for memory operands.  */
        !           532: 
        !           533:   if (unsignedp)
        !           534:     {
        !           535: #ifdef HAVE_extzv
        !           536:       if (HAVE_extzv)
        !           537:        {
        !           538:          /* Get ref to first byte containing part of the field.  */
        !           539:          if (GET_CODE (op0) == MEM)
        !           540:            op0 = change_address (op0, QImode,
        !           541:                                  plus_constant (XEXP (op0, 0), offset));
        !           542: 
        !           543:          /* If op0 is a register, we need it in SImode
        !           544:             to make it acceptable to the format of extv.  */
        !           545:          if (GET_CODE (op0) == SUBREG)
        !           546:            PUT_MODE (op0, SImode);
        !           547:          if (GET_CODE (op0) == REG && GET_MODE (op0) != SImode)
        !           548:            op0 = gen_rtx (SUBREG, SImode, op0, 0);
        !           549: 
        !           550:          if (target == 0
        !           551:              || (flag_force_mem && GET_CODE (target) == MEM))
        !           552:            target = spec_target = gen_reg_rtx (tmode);
        !           553: 
        !           554:          if (GET_MODE (target) != SImode)
        !           555:            {
        !           556:              if (GET_CODE (target) == REG)
        !           557:                spec_target_subreg = target = gen_rtx (SUBREG, SImode, target, 0);
        !           558:              else
        !           559:                target = gen_reg_rtx (SImode);
        !           560:            }
        !           561: 
        !           562:          /* If this machine's extzv insists on a register target,
        !           563:             make sure we have one.  */
        !           564:          if (! (*insn_operand_predicate[(int) CODE_FOR_extzv][0]) (target, SImode))
        !           565:            target = gen_reg_rtx (SImode);
        !           566: 
        !           567:          /* On big-endian machines, we count bits from the most significant.
        !           568:             If the bit field insn does not, we must invert.  */
        !           569: #if defined (BITS_BIG_ENDIAN) != defined (BYTES_BIG_ENDIAN)
        !           570:          bitpos = unit - 1 - bitpos;
        !           571: #endif
        !           572: 
        !           573:          bitsize_rtx = gen_rtx (CONST_INT, VOIDmode, bitsize);
        !           574:          bitpos_rtx = gen_rtx (CONST_INT, VOIDmode, bitpos);
        !           575: 
        !           576:          emit_insn (gen_extzv (protect_from_queue (target, 1),
        !           577:                                op0, bitsize_rtx, bitpos_rtx));
        !           578:        }
        !           579:       else
        !           580: #endif
        !           581:        target = extract_fixed_bit_field (tmode, op0, offset, bitsize, bitpos,
        !           582:                                          target, 1);
        !           583:     }
        !           584:   else
        !           585:     {
        !           586: #ifdef HAVE_extv
        !           587:       if (HAVE_extv)
        !           588:        {
        !           589:          /* Get ref to first byte containing part of the field.  */
        !           590:          if (GET_CODE (op0) == MEM)
        !           591:            op0 = change_address (op0, QImode,
        !           592:                                  plus_constant (XEXP (op0, 0), offset));
        !           593: 
        !           594:          /* If op0 is a register, we need it in QImode
        !           595:             to make it acceptable to the format of extv.  */
        !           596:          if (GET_CODE (op0) == SUBREG)
        !           597:            PUT_MODE (op0, SImode);
        !           598:          if (GET_CODE (op0) == REG && GET_MODE (op0) != SImode)
        !           599:            op0 = gen_rtx (SUBREG, SImode, op0, 0);
        !           600: 
        !           601:          if (target == 0
        !           602:              || (flag_force_mem && GET_CODE (target) == MEM))
        !           603:            target = spec_target = gen_reg_rtx (tmode);
        !           604: 
        !           605:          if (GET_MODE (target) != SImode)
        !           606:            {
        !           607:              if (GET_CODE (target) == REG)
        !           608:                spec_target_subreg = target = gen_rtx (SUBREG, SImode, target, 0);
        !           609:              else
        !           610:                target = gen_reg_rtx (SImode);
        !           611:            }
        !           612: 
        !           613:          /* If this machine's extv insists on a register target,
        !           614:             make sure we have one.  */
        !           615:          if (! (*insn_operand_predicate[(int) CODE_FOR_extzv][0]) (target, SImode))
        !           616:            target = gen_reg_rtx (SImode);
        !           617: 
        !           618:          /* On big-endian machines, we count bits from the most significant.
        !           619:             If the bit field insn does not, we must invert.  */
        !           620: #if defined (BITS_BIG_ENDIAN) != defined (BYTES_BIG_ENDIAN)
        !           621:          bitpos = unit - 1 - bitpos;
        !           622: #endif
        !           623: 
        !           624:          bitsize_rtx = gen_rtx (CONST_INT, VOIDmode, bitsize);
        !           625:          bitpos_rtx = gen_rtx (CONST_INT, VOIDmode, bitpos);
        !           626: 
        !           627:          emit_insn (gen_extv (protect_from_queue (target, 1), op0,
        !           628:                               bitsize_rtx, bitpos_rtx));
        !           629:        }
        !           630:       else
        !           631: #endif
        !           632:        target = extract_fixed_bit_field (tmode, op0, offset, bitsize, bitpos,
        !           633:                                          target, 0);
        !           634:     }
        !           635:   if (target == spec_target)
        !           636:     return target;
        !           637:   if (target == spec_target_subreg)
        !           638:     return spec_target;
        !           639:   if (GET_MODE (target) != tmode && GET_MODE (target) != mode)
        !           640:     return convert_to_mode (tmode, target, unsignedp);
        !           641:   return target;
        !           642: }
        !           643: 
        !           644: /* Extract a bit field using shifts and boolean operations
        !           645:    Returns an rtx to represent the value.
        !           646:    OP0 addresses a register (word) or memory (byte).
        !           647:    BITPOS says which bit within the word or byte the bit field starts in.
        !           648:    OFFSET says how many bytes farther the bit field starts;
        !           649:     it is 0 if OP0 is a register.
        !           650:    BITSIZE says how many bits long the bit field is.
        !           651:     (If OP0 is a register, it may be narrower than SImode,
        !           652:      but BITPOS still counts within a full word,
        !           653:      which is significant on bigendian machines.)
        !           654: 
        !           655:    UNSIGNEDP is nonzero for an unsigned bit field (don't sign-extend value).
        !           656:    If TARGET is nonzero, attempts to store the value there
        !           657:    and return TARGET, but this is not guaranteed.
        !           658:    If TARGET is not used, create a pseudo-reg of mode TMODE for the value.  */
        !           659: 
        !           660: static rtx
        !           661: extract_fixed_bit_field (tmode, op0, offset, bitsize, bitpos, target, unsignedp)
        !           662:      enum machine_mode tmode;
        !           663:      register rtx op0, target;
        !           664:      register int offset, bitsize, bitpos;
        !           665:      int unsignedp;
        !           666: {
        !           667:   int total_bits = BITS_PER_WORD;
        !           668:   enum machine_mode mode;
        !           669:   rtx orig = op0;
        !           670: 
        !           671:   if (GET_CODE (op0) == SUBREG || GET_CODE (op0) == REG)
        !           672:     {
        !           673:       /* Special treatment for a bit field split across two registers.  */
        !           674:       if (bitsize + bitpos > BITS_PER_WORD)
        !           675:        return extract_split_bit_field (op0, bitsize, bitpos, unsignedp);
        !           676:     }
        !           677:   else if (bitsize + bitpos <= BITS_PER_UNIT && ! SLOW_BYTE_ACCESS)
        !           678:     {
        !           679:       /* If the bit field fits entirely in one byte of memory,
        !           680:         let OP0 be that byte.  We must add OFFSET to its address.  */
        !           681:       total_bits = BITS_PER_UNIT;
        !           682:       op0 = change_address (op0, QImode,
        !           683:                            plus_constant (XEXP (op0, 0), offset));
        !           684:     }
        !           685:   else
        !           686:     {
        !           687: #ifdef STRICT_ALIGNMENT
        !           688: #ifndef STRUCTURE_SIZE_BOUNDARY
        !           689:       /* The following code assumes that OP0 is aligned
        !           690:         such that a word can be fetched there.
        !           691:         This could be because words don't need to be aligned,
        !           692:         or because all structures are suitably aligned.  */
        !           693:       abort ();
        !           694: #endif
        !           695: #endif
        !           696: 
        !           697:       /* Get ref to word containing the field.  */
        !           698:       /* Adjust BITPOS to be position within a word,
        !           699:         and OFFSET to be the offset of that word.  */
        !           700:       bitpos += (offset % (BITS_PER_WORD / BITS_PER_UNIT)) * BITS_PER_UNIT;
        !           701:       offset -= (offset % (BITS_PER_WORD / BITS_PER_UNIT));
        !           702:       op0 = change_address (op0, SImode,
        !           703:                            plus_constant (XEXP (op0, 0), offset));
        !           704: 
        !           705:       /* Special treatment for a bit field split across two words.  */
        !           706:       if (bitsize + bitpos > BITS_PER_WORD)
        !           707:        return extract_split_bit_field (op0, bitsize, bitpos, unsignedp);
        !           708:     }
        !           709: 
        !           710:   mode = GET_MODE (op0);
        !           711: 
        !           712: #ifdef BYTES_BIG_ENDIAN
        !           713:   /* BITPOS is the distance between our msb
        !           714:      and that of the containing byte or word.
        !           715:      Convert it to the distance from the lsb.  */
        !           716: 
        !           717:   bitpos = total_bits - bitsize - bitpos;
        !           718: #endif
        !           719:   /* Now BITPOS is always the distance between our lsb
        !           720:      and that of the containing byte or word.
        !           721:      We have reduced the big-endian case to the little-endian case.  */
        !           722: 
        !           723:   if (unsignedp)
        !           724:     {
        !           725:       if (bitpos)
        !           726:        {
        !           727:          /* If the field does not already start at the lsb,
        !           728:             shift it so it does.  */
        !           729:          tree amount = build_int_2 (bitpos, 0);
        !           730:          /* Maybe propagate the target for the shift.  */
        !           731:          /* Certainly do so if we will return the value of the shift.  */
        !           732:          rtx subtarget = (target != 0 && GET_CODE (target) == REG
        !           733:                           && FUNCTION_VALUE_REGNO_P (REGNO (target))
        !           734:                           ? target : 0);
        !           735:          if (tmode != mode) subtarget = 0;
        !           736:          op0 = expand_shift (RSHIFT_EXPR, mode, op0, amount, subtarget, 1);
        !           737:        }
        !           738:       /* Convert the value to the desired mode.  */
        !           739:       if (mode != tmode)
        !           740:        op0 = convert_to_mode (tmode, op0, 1);
        !           741: 
        !           742:       /* Unless the msb of the field used to be the msb when we shifted,
        !           743:         mask out the upper bits.  */
        !           744: 
        !           745:       if ((GET_MODE_BITSIZE (mode) != bitpos + bitsize
        !           746: #if 0
        !           747: #ifdef SLOW_ZERO_EXTEND
        !           748:           /* Always generate an `and' if
        !           749:              we just zero-extended op0 and SLOW_ZERO_EXTEND, since it
        !           750:              will combine fruitfully with the zero-extend. */
        !           751:           || tmode != mode
        !           752: #endif
        !           753: #endif
        !           754:           )
        !           755:          && bitsize < HOST_BITS_PER_INT)
        !           756:        return expand_bit_and (GET_MODE (op0), op0,
        !           757:                               gen_rtx (CONST_INT, VOIDmode, (1 << bitsize) - 1),
        !           758:                               target);
        !           759:       return op0;
        !           760:     }
        !           761: 
        !           762:   /* To extract a signed bit-field, first shift its msb to the msb of the word,
        !           763:      then arithmetic-shift its lsb to the lsb of the word.  */
        !           764:   op0 = force_reg (mode, op0);
        !           765:   if (mode != tmode)
        !           766:     target = 0;
        !           767:   if (GET_MODE_BITSIZE (QImode) < GET_MODE_BITSIZE (mode)
        !           768:       && GET_MODE_BITSIZE (QImode) >= bitsize + bitpos)
        !           769:     mode = QImode, op0 = convert_to_mode (QImode, op0, 0);
        !           770:   if (GET_MODE_BITSIZE (HImode) < GET_MODE_BITSIZE (mode)
        !           771:       && GET_MODE_BITSIZE (HImode) >= bitsize + bitpos)
        !           772:     mode = HImode, op0 = convert_to_mode (HImode, op0, 0);
        !           773:   if (GET_MODE_BITSIZE (mode) != (bitsize + bitpos))
        !           774:     {
        !           775:       tree amount = build_int_2 (GET_MODE_BITSIZE (mode) - (bitsize + bitpos), 0);
        !           776:       /* Maybe propagate the target for the shift.  */
        !           777:       /* Certainly do so if we will return the value of the shift.  */
        !           778:       rtx subtarget = (target != 0 && GET_CODE (target) == REG
        !           779:                       && FUNCTION_VALUE_REGNO_P (REGNO (target))
        !           780:                       ? target : 0);
        !           781:       op0 = expand_shift (LSHIFT_EXPR, mode, op0, amount, subtarget, 1);
        !           782:     }
        !           783: 
        !           784:   return expand_shift (RSHIFT_EXPR, mode, op0,
        !           785:                       build_int_2 (GET_MODE_BITSIZE (mode) - bitsize, 0), 
        !           786:                       target, 0);
        !           787: }
        !           788: 
        !           789: /* Extract a bit field that is split across two words
        !           790:    and return an RTX for the result.
        !           791: 
        !           792:    OP0 is the REG, SUBREG or MEM rtx for the first of the two words.
        !           793:    BITSIZE is the field width; BITPOS, position of its first bit, in the word.
        !           794:    UNSIGNEDP is 1 if should zero-extend the contents; else sign-extend.  */
        !           795: 
        !           796: static rtx
        !           797: extract_split_bit_field (op0, bitsize, bitpos, unsignedp)
        !           798:      rtx op0;
        !           799:      int bitsize, bitpos, unsignedp;
        !           800: {
        !           801:   /* BITSIZE_1 is size of the part in the first word.  */
        !           802:   int bitsize_1 = BITS_PER_WORD - bitpos;
        !           803:   /* BITSIZE_2 is size of the rest (in the following word).  */
        !           804:   int bitsize_2 = bitsize - bitsize_1;
        !           805:   rtx part1, part2, result;
        !           806: 
        !           807:   /* Get the part of the bit field from the first word.  */
        !           808:   part1 = extract_fixed_bit_field (SImode, op0, 0, bitsize_1, bitpos, 0, 1);
        !           809: 
        !           810:   /* Offset op0 by 1 word to get to the following one.  */
        !           811:   if (GET_CODE (op0) == MEM)
        !           812:     op0 = change_address (op0, SImode,
        !           813:                          plus_constant (XEXP (op0, 0), UNITS_PER_WORD));
        !           814:   else if (GET_CODE (op0) == REG)
        !           815:     op0 = gen_rtx (SUBREG, SImode, op0, 1);
        !           816:   else
        !           817:     op0 = gen_rtx (SUBREG, SImode, SUBREG_REG (op0), SUBREG_WORD (op0) + 1);
        !           818: 
        !           819:   /* Get the part of the bit field from the second word.  */
        !           820:   part2 = extract_fixed_bit_field (SImode, op0, 0, bitsize_2, 0, 0, 1);
        !           821: 
        !           822:   /* Shift the more significant part up to fit above the other part.  */
        !           823: #ifdef BYTES_BIG_ENDIAN
        !           824:   part1 = expand_shift (LSHIFT_EXPR, SImode, part1,
        !           825:                        build_int_2 (bitsize_2, 0), 0, 1);
        !           826: #else
        !           827:   part2 = expand_shift (LSHIFT_EXPR, SImode, part2,
        !           828:                        build_int_2 (bitsize_1, 0), 0, 1);
        !           829: #endif
        !           830: 
        !           831:   /* Combine the two parts with bitwise or.  This works
        !           832:      because we extracted both parts as unsigned bit fields.  */
        !           833:   result = expand_binop (SImode, ior_optab, part1, part2, 0, 1,
        !           834:                         OPTAB_LIB_WIDEN);
        !           835: 
        !           836:   /* Unsigned bit field: we are done.  */
        !           837:   if (unsignedp)
        !           838:     return result;
        !           839:   /* Signed bit field: sign-extend with two arithmetic shifts.  */
        !           840:   result = expand_shift (LSHIFT_EXPR, SImode, result,
        !           841:                         build_int_2 (BITS_PER_WORD - bitsize, 0), 0, 0);
        !           842:   return expand_shift (RSHIFT_EXPR, SImode, result,
        !           843:                       build_int_2 (BITS_PER_WORD - bitsize, 0), 0, 0);
        !           844: }
        !           845: 
        !           846: /* Add INC into TARGET.  */
        !           847: 
        !           848: void
        !           849: expand_inc (target, inc)
        !           850:      rtx target, inc;
        !           851: {
        !           852:   rtx value = expand_binop (GET_MODE (target), add_optab,
        !           853:                            target, inc,
        !           854:                            target, 0, OPTAB_LIB_WIDEN);
        !           855:   if (value != target)
        !           856:     emit_move_insn (target, value);
        !           857: }
        !           858: 
        !           859: /* Subtract INC from TARGET.  */
        !           860: 
        !           861: void
        !           862: expand_dec (target, dec)
        !           863:      rtx target, dec;
        !           864: {
        !           865:   rtx value = expand_binop (GET_MODE (target), sub_optab,
        !           866:                            target, dec,
        !           867:                            target, 0, OPTAB_LIB_WIDEN);
        !           868:   if (value != target)
        !           869:     emit_move_insn (target, value);
        !           870: }
        !           871: 
        !           872: /* Output a shift instruction for expression code CODE,
        !           873:    with SHIFTED being the rtx for the value to shift,
        !           874:    and AMOUNT the tree for the amount to shift by.
        !           875:    Store the result in the rtx TARGET, if that is convenient.
        !           876:    If UNSIGNEDP is nonzero, do a logical shift; otherwise, arithmetic.
        !           877:    Return the rtx for where the value is.  */
        !           878: 
        !           879: /* Pastel, for shifts, converts shift count to SImode here
        !           880:    independent of the mode being shifted.
        !           881:    Should that be done in an earlier pass?
        !           882:    It turns out not to matter for C.  */
        !           883: 
        !           884: rtx
        !           885: expand_shift (code, mode, shifted, amount, target, unsignedp)
        !           886:      enum tree_code code;
        !           887:      register enum machine_mode mode;
        !           888:      rtx shifted;
        !           889:      tree amount;
        !           890:      register rtx target;
        !           891:      int unsignedp;
        !           892: {
        !           893:   register rtx op1, temp = 0;
        !           894:   register int left = (code == LSHIFT_EXPR || code == LROTATE_EXPR);
        !           895:   int try;
        !           896:   rtx negated = 0;
        !           897:   int rotate = code == LROTATE_EXPR || code == RROTATE_EXPR;
        !           898: 
        !           899:   /* Previously detected shift-counts computed by NEGATE_EXPR
        !           900:      and shifted in the other direction; but that does not work
        !           901:      on all machines.  */
        !           902: 
        !           903:   op1 = expand_expr (amount, 0, VOIDmode, 0);
        !           904: 
        !           905:   for (try = 0; temp == 0 && try < 3; try++)
        !           906:     {
        !           907:       enum optab_methods methods;
        !           908:       if (try == 0)
        !           909:        methods = OPTAB_DIRECT;
        !           910:       else if (try == 1)
        !           911:        methods = OPTAB_WIDEN;
        !           912:       else
        !           913:        methods = OPTAB_LIB_WIDEN;
        !           914: 
        !           915:       if (rotate)
        !           916:        {
        !           917:          /* Widening does not work for rotation.  */
        !           918:          if (methods != OPTAB_DIRECT)
        !           919:            methods = OPTAB_LIB;
        !           920: 
        !           921:          temp = expand_binop (mode,
        !           922:                               left ? rotl_optab : rotr_optab,
        !           923:                               shifted, op1, target, -1, methods);
        !           924:          /* If there is no shift instruction for the desired direction,
        !           925:             try negating the shift count and shifting in the other direction.
        !           926:             If a machine has only a left shift instruction then we are
        !           927:             entitled to assume it shifts right with negative args.  */
        !           928:          if (temp == 0)
        !           929:            {
        !           930:              if (negated != 0)
        !           931:                ;
        !           932:              else if (GET_CODE (op1) == CONST_INT)
        !           933:                negated = gen_rtx (CONST_INT, VOIDmode, -INTVAL (op1));
        !           934:              else
        !           935:                negated = expand_unop (mode, neg_optab, op1, 0, 0);
        !           936:              temp = expand_binop (mode,
        !           937:                                   left ? rotr_optab : rotl_optab,
        !           938:                                   shifted, negated, target, -1, methods);
        !           939:            }
        !           940:        }
        !           941:       else if (unsignedp)
        !           942:        {
        !           943:          temp = expand_binop (mode,
        !           944:                               left ? lshl_optab : lshr_optab,
        !           945:                               shifted, op1, target, unsignedp, methods);
        !           946:          if (temp == 0 && left)
        !           947:            temp = expand_binop (mode, ashl_optab,
        !           948:                                 shifted, op1, target, unsignedp, methods);
        !           949:          if (temp == 0)
        !           950:            {
        !           951:              if (negated != 0)
        !           952:                ;
        !           953:              else if (GET_CODE (op1) == CONST_INT)
        !           954:                negated = gen_rtx (CONST_INT, VOIDmode, -INTVAL (op1));
        !           955:              else
        !           956:                negated = expand_unop (mode, neg_optab, op1, 0, 0);
        !           957:              temp = expand_binop (mode,
        !           958:                                   left ? lshr_optab : lshl_optab,
        !           959:                                   shifted, negated,
        !           960:                                   target, unsignedp, methods);
        !           961:            }
        !           962: 
        !           963:          if (temp != 0)
        !           964:            return temp;
        !           965:        }
        !           966:       /* Do arithmetic shifts.
        !           967:         Also, if we are going to widen the operand, we can just as well
        !           968:         use an arithmetic right-shift instead of a logical one.  */
        !           969:       if (! rotate && (! unsignedp || (! left && methods == OPTAB_WIDEN)))
        !           970:        {
        !           971:          /* Arithmetic shift */
        !           972: 
        !           973:          temp = expand_binop (mode,
        !           974:                               left ? ashl_optab : ashr_optab,
        !           975:                               shifted, op1, target, unsignedp, methods);
        !           976:          if (temp == 0)
        !           977:            {
        !           978:              if (negated != 0)
        !           979:                ;
        !           980:              else if (GET_CODE (op1) == CONST_INT)
        !           981:                negated = gen_rtx (CONST_INT, VOIDmode, -INTVAL (op1));
        !           982:              else
        !           983:                negated = expand_unop (mode, neg_optab, op1, 0, 0);
        !           984:              temp = expand_binop (mode,
        !           985:                                   left ? ashr_optab : ashl_optab,
        !           986:                                   shifted, negated, target, unsignedp, methods);
        !           987:            }
        !           988:          if (temp != 0)
        !           989:            return temp;
        !           990:        }
        !           991: 
        !           992:       if (unsignedp)
        !           993:        {
        !           994:          /* No logical shift insn in either direction =>
        !           995:             try a bit-field extract instruction if we have one.  */
        !           996: #ifdef HAVE_extzv
        !           997: #ifndef BITS_BIG_ENDIAN
        !           998:          if (HAVE_extzv && !left
        !           999:              && ((methods == OPTAB_DIRECT && mode == SImode)
        !          1000:                  || (methods == OPTAB_WIDEN
        !          1001:                      && GET_MODE_SIZE (mode) < GET_MODE_SIZE (SImode))))
        !          1002:            {
        !          1003:              rtx shifted1 = convert_to_mode (SImode, shifted, 1);
        !          1004:              rtx target1 = target;
        !          1005: 
        !          1006:              /* If -fforce-mem, don't let the operand be in memory.  */
        !          1007:              if (flag_force_mem && GET_CODE (shifted1) == MEM)
        !          1008:                shifted1 = force_not_mem (shifted1);
        !          1009: 
        !          1010:              /* If this machine's extzv insists on a register for
        !          1011:                 operand 1, arrange for that.  */
        !          1012:              if (! ((*insn_operand_predicate[(int) CODE_FOR_extzv][1])
        !          1013:                     (shifted1, SImode)))
        !          1014:                shifted1 = force_reg (SImode, shifted1);
        !          1015: 
        !          1016:              /* If we don't have or cannot use a suggested target,
        !          1017:                 make a place for the result, in the proper mode.  */
        !          1018:              if (methods == OPTAB_WIDEN || target1 == 0
        !          1019:                  || ! ((*insn_operand_predicate[(int) CODE_FOR_extzv][0])
        !          1020:                        (target1, SImode)))
        !          1021:                target1 = gen_reg_rtx (SImode);
        !          1022: 
        !          1023:              /* If this machine's extzv insists on a register for
        !          1024:                 operand 3, arrange for that.  */
        !          1025:              if (! ((*insn_operand_predicate[(int) CODE_FOR_extzv][3])
        !          1026:                     (op1, SImode)))
        !          1027:                op1 = force_reg (SImode, op1);
        !          1028: 
        !          1029:              op1 = protect_from_queue (op1, 1);
        !          1030: 
        !          1031:              /* TEMP gets the width of the bit field to extract:
        !          1032:                 wordsize minus # bits to shift by.  */
        !          1033:              if (GET_CODE (op1) == CONST_INT)
        !          1034:                temp = gen_rtx (CONST_INT, VOIDmode,
        !          1035:                                (GET_MODE_BITSIZE (mode) - INTVAL (op1)));
        !          1036:              else
        !          1037:                temp = expand_binop (SImode, sub_optab,
        !          1038:                                     gen_rtx (CONST_INT, VOIDmode,
        !          1039:                                              GET_MODE_BITSIZE (mode)),
        !          1040:                                     op1, gen_reg_rtx (SImode),
        !          1041:                                     0, OPTAB_LIB_WIDEN);
        !          1042:              /* Now extract with width TEMP, omitting OP1 least sig bits.  */
        !          1043:              emit_insn (gen_extzv (protect_from_queue (target1, 1),
        !          1044:                                    protect_from_queue (shifted1, 0),
        !          1045:                                    temp, op1));
        !          1046:              return convert_to_mode (mode, target1, 1);
        !          1047:            }
        !          1048:          /* Can also do logical shift with signed bit-field extract
        !          1049:             followed by inserting the bit-field at a different position.
        !          1050:             That strategy is not yet implemented.  */
        !          1051: #endif /* not BITS_BIG_ENDIAN */
        !          1052: #endif /* HAVE_extzv */
        !          1053:          /* We have failed to generate the logical shift and will abort.  */
        !          1054:        }
        !          1055:     }
        !          1056:   if (temp == 0)
        !          1057:     abort ();
        !          1058:   return temp;
        !          1059: }
        !          1060: 
        !          1061: /* Output an instruction or two to bitwise-and OP0 with OP1
        !          1062:    in mode MODE, with output to TARGET if convenient and TARGET is not zero.
        !          1063:    Returns where the result is.  */
        !          1064: 
        !          1065: rtx
        !          1066: expand_bit_and (mode, op0, op1, target)
        !          1067:      enum machine_mode mode;
        !          1068:      rtx op0, op1, target;
        !          1069: {
        !          1070:   register rtx temp;
        !          1071: 
        !          1072:   /* First try to open-code it directly.  */
        !          1073:   temp = expand_binop (mode, and_optab, op0, op1, target, 1, OPTAB_DIRECT);
        !          1074:   if (temp == 0)
        !          1075:     {
        !          1076:       rtx compl;
        !          1077:       /* If that fails, try to open code using a clear-bits insn.  */
        !          1078:       if (GET_CODE (op1) == CONST_INT
        !          1079:          && GET_MODE_BITSIZE (mode) < HOST_BITS_PER_INT)
        !          1080:        compl = gen_rtx (CONST_INT, VOIDmode,
        !          1081:                         ((1 << GET_MODE_BITSIZE (mode)) - 1) & ~INTVAL (op1));
        !          1082:       else
        !          1083:        compl = expand_unop (mode, one_cmpl_optab, op1, 0, 1);
        !          1084:       temp = expand_binop (mode, andcb_optab, op0, compl, target,
        !          1085:                           1, OPTAB_DIRECT);
        !          1086:     }
        !          1087:   if (temp == 0)
        !          1088:     /* If still no luck, try library call or wider modes.  */
        !          1089:     temp = expand_binop (mode, and_optab, op0, op1, target,
        !          1090:                         1, OPTAB_LIB_WIDEN);
        !          1091: 
        !          1092:   if (temp == 0)
        !          1093:     abort ();
        !          1094:   return temp;
        !          1095: }
        !          1096: 
        !          1097: /* Perform a multiplication and return an rtx for the result.
        !          1098:    MODE is mode of value; OP0 and OP1 are what to multiply (rtx's);
        !          1099:    TARGET is a suggestion for where to store the result (an rtx).
        !          1100: 
        !          1101:    We check specially for a constant integer as OP1.
        !          1102:    If you want this check for OP0 as well, then before calling
        !          1103:    you should swap the two operands if OP0 would be constant.  */
        !          1104: 
        !          1105: rtx
        !          1106: expand_mult (mode, op0, op1, target, unsignedp)
        !          1107:      enum machine_mode mode;
        !          1108:      register rtx op0, op1, target;
        !          1109:      int unsignedp;
        !          1110: {
        !          1111:   /* Don't use the function value register as a target
        !          1112:      since we have to read it as well as write it,
        !          1113:      and function-inlining gets confused by this.  */
        !          1114:   if (target && REG_P (target) && FUNCTION_VALUE_REGNO_P (REGNO (target)))
        !          1115:     target = 0;
        !          1116: 
        !          1117:   if (GET_CODE (op1) == CONST_INT)
        !          1118:     {
        !          1119:       register int foo;
        !          1120:       int bar;
        !          1121:       int negate = INTVAL (op1) < 0;
        !          1122:       int absval = INTVAL (op1) * (negate ? -1 : 1);
        !          1123: 
        !          1124:       /* Is multiplier a power of 2, or minus that?  */
        !          1125:       foo = exact_log2 (absval);
        !          1126:       if (foo >= 0)
        !          1127:        {
        !          1128:          rtx tem =  expand_shift (LSHIFT_EXPR, mode, op0,
        !          1129:                                   build_int_2 (foo, 0),
        !          1130:                                   target, 0);
        !          1131:          return negate ? negate_rtx (tem) : tem;
        !          1132:        }
        !          1133:       /* Is multiplier a sum of two powers of 2, or minus that?  */
        !          1134:       bar = floor_log2 (absval);
        !          1135:       foo = exact_log2 (absval - (1 << bar));
        !          1136:       if (bar >= 0 && foo >= 0)
        !          1137:        {
        !          1138:          rtx pow1 = ((foo == 0) ? op0
        !          1139:                      : expand_shift (LSHIFT_EXPR, mode, op0,
        !          1140:                                      build_int_2 (foo, 0),
        !          1141:                                      0, 0));
        !          1142:          rtx pow2 = expand_shift (LSHIFT_EXPR, mode, op0,
        !          1143:                                   build_int_2 (bar, 0),
        !          1144:                                   0, 0);
        !          1145:          rtx tem = force_operand (gen_rtx (PLUS, mode, pow1, pow2), target);
        !          1146:          return negate ? negate_rtx (tem) : tem;
        !          1147:        }
        !          1148:     }
        !          1149:   /* This used to use umul_optab if unsigned,
        !          1150:      but I think that for non-widening multiply there is no difference
        !          1151:      between signed and unsigned.  */
        !          1152:   op0 = expand_binop (mode, smul_optab,
        !          1153:                      op0, op1, target, unsignedp, OPTAB_LIB_WIDEN);
        !          1154:   if (op0 == 0)
        !          1155:     abort ();
        !          1156:   return op0;
        !          1157: }
        !          1158: 
        !          1159: /* Emit the code to divide OP0 by OP1, putting the result in TARGET
        !          1160:    if that is convenient, and returning where the result is.
        !          1161:    You may request either the quotient or the remainder as the result;
        !          1162:    specify REM_FLAG nonzero to get the remainder.
        !          1163: 
        !          1164:    CODE is the expression code for which kind of division this is;
        !          1165:    it controls how rounding is done.  MODE is the machine mode to use.
        !          1166:    UNSIGNEDP nonzero means do unsigned division.  */
        !          1167: 
        !          1168: /* ??? For CEIL_MOD_EXPR, can compute incorrect remainder with ANDI
        !          1169:    and then correct it by or'ing in missing high bits
        !          1170:    if result of ANDI is nonzero.
        !          1171:    For ROUND_MOD_EXPR, can use ANDI and then sign-extend the result.
        !          1172:    This could optimize to a bfexts instruction.
        !          1173:    But C doesn't use these operations, so their optimizations are
        !          1174:    left for later.  */
        !          1175: 
        !          1176: rtx
        !          1177: expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
        !          1178:      int rem_flag;
        !          1179:      enum tree_code code;
        !          1180:      enum machine_mode mode;
        !          1181:      register rtx op0, op1, target;
        !          1182:      int unsignedp;
        !          1183: {
        !          1184:   register rtx label;
        !          1185:   register rtx temp;
        !          1186:   int log = -1;
        !          1187:   int can_clobber_op0;
        !          1188:   int mod_insn_no_good = 0;
        !          1189:   rtx adjusted_op0 = op0;
        !          1190: 
        !          1191:   /* Don't use the function value register as a target
        !          1192:      since we have to read it as well as write it,
        !          1193:      and function-inlining gets confused by this.  */
        !          1194:   if (target && REG_P (target) && FUNCTION_VALUE_REGNO_P (REGNO (target)))
        !          1195:     target = 0;
        !          1196: 
        !          1197:   if (target == 0)
        !          1198:     {
        !          1199:       target = gen_reg_rtx (mode);
        !          1200:     }
        !          1201: 
        !          1202:   /* Don't clobber an operand while doing a multi-step calculation.  */
        !          1203:   if ((rem_flag && rtx_equal_p (target, op0))
        !          1204:       || rtx_equal_p (target, op1))
        !          1205:     target = gen_reg_rtx (mode);
        !          1206: 
        !          1207:   can_clobber_op0 = (GET_CODE (op0) == REG && op0 == target);
        !          1208: 
        !          1209:   if (GET_CODE (op1) == CONST_INT)
        !          1210:     log = exact_log2 (INTVAL (op1));
        !          1211: 
        !          1212:   /* If log is >= 0, we are dividing by 2**log, and will do it by shifting,
        !          1213:      which is really floor-division.  Otherwise we will really do a divide,
        !          1214:      and we assume that is trunc-division.
        !          1215: 
        !          1216:      We must correct the dividend by adding or subtracting something
        !          1217:      based on the divisor, in order to do the kind of rounding specified
        !          1218:      by CODE.  The correction depends on what kind of rounding is actually
        !          1219:      available, and that depends on whether we will shift or divide.  */
        !          1220: 
        !          1221:   switch (code)
        !          1222:     {
        !          1223:     case TRUNC_MOD_EXPR:
        !          1224:     case TRUNC_DIV_EXPR:
        !          1225:       if (log >= 0 && ! unsignedp)
        !          1226:        {
        !          1227:          label = gen_label_rtx ();
        !          1228:          if (! can_clobber_op0)
        !          1229:            adjusted_op0 = copy_to_suggested_reg (adjusted_op0, target);
        !          1230:          emit_cmp_insn (adjusted_op0, const0_rtx, 0, 0);
        !          1231:          emit_jump_insn (gen_bge (label));
        !          1232:          expand_inc (adjusted_op0, plus_constant (op1, -1));
        !          1233:          emit_label (label);
        !          1234:          mod_insn_no_good = 1;
        !          1235:        }
        !          1236:       break;
        !          1237: 
        !          1238:     case FLOOR_DIV_EXPR:
        !          1239:     case FLOOR_MOD_EXPR:
        !          1240:       if (log < 0 && ! unsignedp)
        !          1241:        {
        !          1242:          label = gen_label_rtx ();
        !          1243:          if (! can_clobber_op0)
        !          1244:            adjusted_op0 = copy_to_suggested_reg (adjusted_op0, target);
        !          1245:          emit_cmp_insn (adjusted_op0, const0_rtx, 0, 0);
        !          1246:          emit_jump_insn (gen_bge (label));
        !          1247:          expand_dec (adjusted_op0, op1);
        !          1248:          expand_inc (adjusted_op0, const1_rtx);
        !          1249:          emit_label (label);
        !          1250:          mod_insn_no_good = 1;
        !          1251:        }
        !          1252:       break;
        !          1253: 
        !          1254:     case CEIL_DIV_EXPR:
        !          1255:     case CEIL_MOD_EXPR:
        !          1256:       if (! can_clobber_op0)
        !          1257:        adjusted_op0 = copy_to_suggested_reg (adjusted_op0, target);
        !          1258:       if (log < 0)
        !          1259:        {
        !          1260:          if (! unsignedp)
        !          1261:            {
        !          1262:              label = gen_label_rtx ();
        !          1263:              emit_cmp_insn (adjusted_op0, const0_rtx, 0, 0);
        !          1264:              emit_jump_insn (gen_ble (label));
        !          1265:            }
        !          1266:          expand_inc (adjusted_op0, op1);
        !          1267:          expand_dec (adjusted_op0, const1_rtx);
        !          1268:          if (! unsignedp)
        !          1269:            emit_label (label);
        !          1270:        }
        !          1271:       else
        !          1272:        {
        !          1273:          adjusted_op0 = expand_binop (GET_MODE (target), add_optab,
        !          1274:                                       adjusted_op0, plus_constant (op1, -1),
        !          1275:                                       0, 0, OPTAB_LIB_WIDEN);
        !          1276:        }
        !          1277:       mod_insn_no_good = 1;
        !          1278:       break;
        !          1279: 
        !          1280:     case ROUND_DIV_EXPR:
        !          1281:     case ROUND_MOD_EXPR:
        !          1282:       if (! can_clobber_op0)
        !          1283:        adjusted_op0 = copy_to_suggested_reg (adjusted_op0, target);
        !          1284:       if (log < 0)
        !          1285:        {
        !          1286:          op1 = expand_shift (RSHIFT_EXPR, mode, op1, integer_one_node, 0, 0);
        !          1287:          if (! unsignedp)
        !          1288:            {
        !          1289:              label = gen_label_rtx ();
        !          1290:              emit_cmp_insn (adjusted_op0, const0_rtx, 0, 0);
        !          1291:              emit_jump_insn (gen_bge (label));
        !          1292:              expand_unop (mode, neg_optab, op1, op1, 0);
        !          1293:              emit_label (label);
        !          1294:            }
        !          1295:          expand_inc (adjusted_op0, op1);
        !          1296:        }
        !          1297:       else
        !          1298:        {
        !          1299:          op1 = gen_rtx (CONST_INT, VOIDmode, INTVAL (op1) / 2);
        !          1300:          expand_inc (adjusted_op0, op1);
        !          1301:        }
        !          1302:       mod_insn_no_good = 1;
        !          1303:       break;
        !          1304:     }
        !          1305: 
        !          1306:   if (rem_flag && !mod_insn_no_good)
        !          1307:     {
        !          1308:       /* Try to produce the remainder directly */
        !          1309:       if (log >= 0)
        !          1310:        {
        !          1311:          return expand_bit_and (mode, adjusted_op0,
        !          1312:                                 gen_rtx (CONST_INT, VOIDmode,
        !          1313:                                          INTVAL (op1) - 1),
        !          1314:                                 target);
        !          1315:        }
        !          1316:       else
        !          1317:        {
        !          1318:          /* See if we can do remainder without a library call.  */
        !          1319:          temp = expand_binop (mode,
        !          1320:                               unsignedp ? umod_optab : smod_optab,
        !          1321:                               adjusted_op0, op1, target,
        !          1322:                               unsignedp, OPTAB_WIDEN);
        !          1323:          if (temp != 0)
        !          1324:            return temp;
        !          1325:          /* No luck there.
        !          1326:             Can we do remainder and divide at once without a library call?  */
        !          1327:          temp = gen_reg_rtx (mode);
        !          1328:          if (expand_twoval_binop (unsignedp ? udivmod_optab : sdivmod_optab,
        !          1329:                                   adjusted_op0, op1,
        !          1330:                                   0, temp, unsignedp))
        !          1331:            return temp;
        !          1332:          temp = 0;
        !          1333:        }
        !          1334:     }
        !          1335: 
        !          1336:   /* Produce the quotient.  */
        !          1337:   if (log >= 0)
        !          1338:     temp = expand_shift (RSHIFT_EXPR, mode, adjusted_op0,
        !          1339:                         build_int_2 (exact_log2 (INTVAL (op1)), 0),
        !          1340:                         target, unsignedp);
        !          1341:   else if (rem_flag && !mod_insn_no_good)
        !          1342:     /* If producing quotient in order to subtract for remainder,
        !          1343:        and a remainder subroutine would be ok,
        !          1344:        don't use a divide subroutine.  */
        !          1345:     temp = expand_binop (mode, unsignedp ? udiv_optab : sdiv_optab,
        !          1346:                         adjusted_op0, op1, target,
        !          1347:                         unsignedp, OPTAB_WIDEN);
        !          1348:   else
        !          1349:     temp = expand_binop (mode, unsignedp ? udiv_optab : sdiv_optab,
        !          1350:                         adjusted_op0, op1, target,
        !          1351:                         unsignedp, OPTAB_LIB_WIDEN);
        !          1352: 
        !          1353:   /* If we really want the remainder, get it by subtraction.  */
        !          1354:   if (rem_flag)
        !          1355:     {
        !          1356:       if (temp == 0)
        !          1357:        {
        !          1358:          /* No divide instruction either.  Use library for remainder.  */
        !          1359:          temp = expand_binop (mode,
        !          1360:                               unsignedp ? umod_optab : smod_optab,
        !          1361:                               op0, op1, target,
        !          1362:                               unsignedp, OPTAB_LIB_WIDEN);
        !          1363:        }
        !          1364:       else
        !          1365:        {
        !          1366:          /* We divided.  Now finish doing X - Y * (X / Y).  */
        !          1367:          temp = expand_mult (mode, temp, op1, temp, unsignedp);
        !          1368:          if (! temp) abort ();
        !          1369:          temp = expand_binop (mode, sub_optab, op0,
        !          1370:                               temp, target, unsignedp, OPTAB_LIB_WIDEN);
        !          1371:        }
        !          1372:     }
        !          1373: 
        !          1374:   if (temp == 0)
        !          1375:     abort ();
        !          1376:   return temp;
        !          1377: }

unix.superglobalmegacorp.com

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