diff options
author | Richard Stallman <rms@gnu.org> | 1993-07-05 03:30:59 +0000 |
---|---|---|
committer | Richard Stallman <rms@gnu.org> | 1993-07-05 03:30:59 +0000 |
commit | 06c94bceebd6f69c22f919c6b6e3673714dfb2f5 (patch) | |
tree | 2d19aa58ac5fede8a2fb03708c3949d440d8d415 /gcc/expmed.c | |
parent | 626e18ea3f0de2ff5ed906ceca18a3faf44b1759 (diff) | |
download | gcc-06c94bceebd6f69c22f919c6b6e3673714dfb2f5.zip gcc-06c94bceebd6f69c22f919c6b6e3673714dfb2f5.tar.gz gcc-06c94bceebd6f69c22f919c6b6e3673714dfb2f5.tar.bz2 |
(store_split_bit_field, extract_split_bit_field):
Handle fields split across more than 2 aligned units.
From-SVN: r4840
Diffstat (limited to 'gcc/expmed.c')
-rw-r--r-- | gcc/expmed.c | 243 |
1 files changed, 113 insertions, 130 deletions
diff --git a/gcc/expmed.c b/gcc/expmed.c index 6fb8579..ed07d5a 100644 --- a/gcc/expmed.c +++ b/gcc/expmed.c @@ -514,10 +514,6 @@ store_fixed_bit_field (op0, offset, bitsize, bitpos, value, struct_align) int all_zero = 0; int all_one = 0; - /* Add OFFSET to OP0's address (if it is in memory) - and if a single byte contains the whole bit field - change OP0 to a byte. */ - /* There is a case not handled here: a structure with a known alignment of just a halfword and a field split across two aligned halfwords within the structure. @@ -532,7 +528,8 @@ store_fixed_bit_field (op0, offset, bitsize, bitpos, value, struct_align) /* Special treatment for a bit field split across two registers. */ if (bitsize + bitpos > BITS_PER_WORD) { - store_split_bit_field (op0, bitsize, bitpos, value, BITS_PER_WORD); + store_split_bit_field (op0, bitsize, bitpos, + value, BITS_PER_WORD); return; } } @@ -550,7 +547,8 @@ store_fixed_bit_field (op0, offset, bitsize, bitpos, value, struct_align) { /* The only way this should occur is if the field spans word boundaries. */ - store_split_bit_field (op0, bitsize, bitpos + offset * BITS_PER_UNIT, + store_split_bit_field (op0, + bitsize, bitpos + offset * BITS_PER_UNIT, value, struct_align); return; } @@ -662,12 +660,16 @@ store_fixed_bit_field (op0, offset, bitsize, bitpos, value, struct_align) emit_move_insn (op0, temp); } -/* Store a bit field that is split across two words. +/* Store a bit field that is split across multiple accessible memory objects. - OP0 is the REG, SUBREG or MEM rtx for the first of the two words. + OP0 is the REG, SUBREG or MEM rtx for the first of the objects. BITSIZE is the field width; BITPOS the position of its first bit (within the word). - VALUE is the value to store. */ + VALUE is the value to store. + ALIGN is the known alignment of OP0, measured in bytes. + This is also the size of the memory objects to be used. + + This does not yet handle fields wider than BITS_PER_WORD. */ static void store_split_bit_field (op0, bitsize, bitpos, value, align) @@ -676,94 +678,67 @@ store_split_bit_field (op0, bitsize, bitpos, value, align) rtx value; int align; { - /* BITSIZE_1 is size of the part in the first word. */ - int bitsize_1 = BITS_PER_WORD - bitpos % BITS_PER_WORD; - /* BITSIZE_2 is size of the rest (in the following word). */ - int bitsize_2 = bitsize - bitsize_1; - rtx part1, part2; - int unit = GET_CODE (op0) == MEM ? BITS_PER_UNIT : BITS_PER_WORD; - int offset = bitpos / unit; + int unit = align * BITS_PER_UNIT; rtx word; - - /* The field must span exactly one word boundary. */ - if (bitpos / BITS_PER_WORD != (bitpos + bitsize - 1) / BITS_PER_WORD - 1) - abort (); - - if (GET_MODE (value) != VOIDmode) - value = convert_to_mode (word_mode, value, 1); + int bitsdone = 0; if (GET_CODE (value) == CONST_DOUBLE - && (part1 = gen_lowpart_common (word_mode, value)) != 0) - value = part1; + && (word = gen_lowpart_common (word_mode, value)) != 0) + value = word; if (CONSTANT_P (value) && GET_CODE (value) != CONST_INT) value = copy_to_mode_reg (word_mode, value); - /* Split the value into two parts: - PART1 gets that which goes in the first word; PART2 the other. */ -#if BYTES_BIG_ENDIAN - /* PART1 gets the more significant part. */ - if (GET_CODE (value) == CONST_INT) - { - part1 = GEN_INT ((unsigned HOST_WIDE_INT) (INTVAL (value)) >> bitsize_2); - part2 = GEN_INT ((unsigned HOST_WIDE_INT) (INTVAL (value)) - & (((HOST_WIDE_INT) 1 << bitsize_2) - 1)); - } - else + while (bitsdone < bitsize) { - part1 = extract_fixed_bit_field (word_mode, value, 0, bitsize_1, - BITS_PER_WORD - bitsize, NULL_RTX, 1, - BITS_PER_WORD); - part2 = extract_fixed_bit_field (word_mode, value, 0, bitsize_2, - BITS_PER_WORD - bitsize_2, NULL_RTX, 1, - BITS_PER_WORD); - } -#else - /* PART1 gets the less significant part. */ - if (GET_CODE (value) == CONST_INT) - { - part1 = GEN_INT ((unsigned HOST_WIDE_INT) (INTVAL (value)) - & (((HOST_WIDE_INT) 1 << bitsize_1) - 1)); - part2 = GEN_INT ((unsigned HOST_WIDE_INT) (INTVAL (value)) >> bitsize_1); - } - else - { - part1 = extract_fixed_bit_field (word_mode, value, 0, bitsize_1, 0, - NULL_RTX, 1, BITS_PER_WORD); - part2 = extract_fixed_bit_field (word_mode, value, 0, bitsize_2, - bitsize_1, NULL_RTX, 1, BITS_PER_WORD); - } -#endif + int thissize; + rtx part, word; + int thispos; + int offset; - /* Store PART1 into the first word. If OP0 is a MEM, pass OP0 and the - offset computed above. Otherwise, get the proper word and pass an - offset of zero. */ - word = (GET_CODE (op0) == MEM ? op0 - : operand_subword (op0, offset, 1, GET_MODE (op0))); - if (word == 0) - abort (); + offset = (bitpos + bitsdone) / unit; + thispos = (bitpos + bitsdone) % unit; - store_fixed_bit_field (word, GET_CODE (op0) == MEM ? offset : 0, - bitsize_1, bitpos % unit, part1, align); + thissize = unit - offset * BITS_PER_UNIT % unit; - /* Offset op0 by 1 word to get to the following one. */ - if (GET_CODE (op0) == SUBREG) - word = operand_subword (SUBREG_REG (op0), SUBREG_WORD (op0) + offset + 1, - 1, VOIDmode); - else if (GET_CODE (op0) == MEM) - word = op0; - else - word = operand_subword (op0, offset + 1, 1, GET_MODE (op0)); +#if BYTES_BIG_ENDIAN + /* Fetch successively less significant portions. */ + if (GET_CODE (value) == CONST_INT) + part = GEN_INT (((unsigned HOST_WIDE_INT) (INTVAL (value)) + >> (bitsize - bitsdone - thissize)) + & (((HOST_WIDE_INT) 1 << thissize) - 1)); + else + /* The args are chosen so that the last part + includes the lsb. */ + part = extract_fixed_bit_field (word_mode, value, 0, thissize, + BITS_PER_WORD - bitsize + bitsdone, + NULL_RTX, 1, align); +#else + /* Fetch successively more significant portions. */ + if (GET_CODE (value) == CONST_INT) + part = GEN_INT (((unsigned HOST_WIDE_INT) (INTVAL (value)) >> bitsdone) + & (((HOST_WIDE_INT) 1 << thissize) - 1)); + else + part = extract_fixed_bit_field (word_mode, value, 0, thissize, + bitsdone, NULL_RTX, 1, align); +#endif - if (word == 0) - abort (); + /* If OP0 is a register, then handle OFFSET here. + In the register case, UNIT must be a whole word. */ + if (GET_CODE (op0) == SUBREG || GET_CODE (op0) == REG) + { + word = operand_subword (op0, offset, 1, GET_MODE (op0)); + offset = 0; + } + else + word = op0; - /* Store PART2 into the second word. */ - store_fixed_bit_field (word, - (GET_CODE (op0) == MEM - ? CEIL (offset + 1, UNITS_PER_WORD) * UNITS_PER_WORD - : 0), - bitsize_2, 0, part2, align); + if (word == 0) + abort (); + + store_fixed_bit_field (word, offset, thissize, thispos, part, align); + bitsdone += thissize; + } } /* Generate code to extract a byte-field from STR_RTX @@ -1449,65 +1424,73 @@ lshift_value (mode, value, bitpos, bitsize) OP0 is the REG, SUBREG or MEM rtx for the first of the two words. BITSIZE is the field width; BITPOS, position of its first bit, in the word. - UNSIGNEDP is 1 if should zero-extend the contents; else sign-extend. */ + UNSIGNEDP is 1 if should zero-extend the contents; else sign-extend. + + ALIGN is the known alignment of OP0, measured in bytes. + This is also the size of the memory objects to be used. */ static rtx extract_split_bit_field (op0, bitsize, bitpos, unsignedp, align) rtx op0; int bitsize, bitpos, unsignedp, align; { - /* BITSIZE_1 is size of the part in the first word. */ - int bitsize_1 = BITS_PER_WORD - bitpos % BITS_PER_WORD; - /* BITSIZE_2 is size of the rest (in the following word). */ - int bitsize_2 = bitsize - bitsize_1; - rtx part1, part2, result; - int unit = GET_CODE (op0) == MEM ? BITS_PER_UNIT : BITS_PER_WORD; - int offset = bitpos / unit; - rtx word; - - /* The field must span exactly one word boundary. */ - if (bitpos / BITS_PER_WORD != (bitpos + bitsize - 1) / BITS_PER_WORD - 1) - abort (); + int unit = align * BITS_PER_UNIT; + int bitsdone = 0; + rtx result; + int first = 1; - /* Get the part of the bit field from the first word. If OP0 is a MEM, - pass OP0 and the offset computed above. Otherwise, get the proper - word and pass an offset of zero. */ - word = (GET_CODE (op0) == MEM ? op0 - : operand_subword_force (op0, offset, GET_MODE (op0))); - part1 = extract_fixed_bit_field (word_mode, word, - GET_CODE (op0) == MEM ? offset : 0, - bitsize_1, bitpos % unit, NULL_RTX, - 1, align); - - /* Offset op0 by 1 word to get to the following one. */ - if (GET_CODE (op0) == SUBREG) - word = operand_subword_force (SUBREG_REG (op0), - SUBREG_WORD (op0) + offset + 1, VOIDmode); - else if (GET_CODE (op0) == MEM) - word = op0; - else - word = operand_subword_force (op0, offset + 1, GET_MODE (op0)); + while (bitsdone < bitsize) + { + int thissize; + rtx part, word; + int thispos; + int offset; + + offset = (bitpos + bitsdone) / unit; + thispos = (bitpos + bitsdone) % unit; + + thissize = unit - offset * BITS_PER_UNIT % unit; + + /* If OP0 is a register, then handle OFFSET here. + In the register case, UNIT must be a whole word. */ + if (GET_CODE (op0) == SUBREG || GET_CODE (op0) == REG) + { + word = operand_subword_force (op0, offset, GET_MODE (op0)); + offset = 0; + } + else + word = op0; + + if (word == 0) + abort (); - /* Get the part of the bit field from the second word. */ - part2 = extract_fixed_bit_field (word_mode, word, - (GET_CODE (op0) == MEM - ? CEIL (offset + 1, UNITS_PER_WORD) * UNITS_PER_WORD - : 0), - bitsize_2, 0, NULL_RTX, 1, align); + /* Extract the parts in bit-counting order, + whose meaning is determined by BYTES_PER_UNIT. */ + part = extract_fixed_bit_field (word_mode, word, offset, + thissize, thispos, 0, 1, align); + bitsdone += thissize; - /* Shift the more significant part up to fit above the other part. */ + /* Shift this part into place for the result. */ #if BYTES_BIG_ENDIAN - part1 = expand_shift (LSHIFT_EXPR, word_mode, part1, - build_int_2 (bitsize_2, 0), 0, 1); + if (bitsize != bitsdone) + part = expand_shift (LSHIFT_EXPR, word_mode, part, + build_int_2 (bitsize - bitsdone, 0), 0, 1); #else - part2 = expand_shift (LSHIFT_EXPR, word_mode, part2, - build_int_2 (bitsize_1, 0), 0, 1); + if (bitsdone != 0) + part = expand_shift (LSHIFT_EXPR, word_mode, part, + build_int_2 (bitsdone, 0), 0, 1); #endif - /* Combine the two parts with bitwise or. This works - because we extracted both parts as unsigned bit fields. */ - result = expand_binop (word_mode, ior_optab, part1, part2, NULL_RTX, 1, - OPTAB_LIB_WIDEN); + if (first) + result = part; + else + /* Combine the parts with bitwise or. This works + because we extracted each part as an unsigned bit field. */ + result = expand_binop (word_mode, ior_optab, part, result, NULL_RTX, 1, + OPTAB_LIB_WIDEN); + + first = 0; + } /* Unsigned bit field: we are done. */ if (unsignedp) |