Annotation of researchv10dc/cmd/gcc/expmed.c, revision 1.1.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.