aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorDoug Evans <dje@gnu.org>1995-01-14 06:19:31 +0000
committerDoug Evans <dje@gnu.org>1995-01-14 06:19:31 +0000
commit77295decc864d07b52e926267f792f303159dcae (patch)
tree2334c5522fd484510c51bf4fc45d9eea68072804 /gcc
parent7726fc45eeb1e9088947f16ba80bf3f5a24dc4b5 (diff)
downloadgcc-77295decc864d07b52e926267f792f303159dcae.zip
gcc-77295decc864d07b52e926267f792f303159dcae.tar.gz
gcc-77295decc864d07b52e926267f792f303159dcae.tar.bz2
(extract_bit_field, fields bigger than word case): Count subwords in target.
(extract_bit_field, fields bigger than word case): Count subwords in target. Zero remaining upper bits if unsigned. From-SVN: r8756
Diffstat (limited to 'gcc')
-rw-r--r--gcc/expmed.c32
1 files changed, 29 insertions, 3 deletions
diff --git a/gcc/expmed.c b/gcc/expmed.c
index b2862b6..6ff8b2b 100644
--- a/gcc/expmed.c
+++ b/gcc/expmed.c
@@ -847,6 +847,10 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
offset += SUBREG_WORD (op0);
op0 = SUBREG_REG (op0);
}
+
+ /* ??? We currently assume TARGET is at least as big as BITSIZE.
+ If that's wrong, the solution is to test for it and set TARGET to 0
+ if needed. */
/* If OP0 is a register, BITPOS must count within a word.
But as we have it, it counts within whatever size OP0 now has.
@@ -909,7 +913,11 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
{
/* If I is 0, use the low-order word in both field and target;
if I is 1, use the next to lowest word; and so on. */
- int wordnum = (WORDS_BIG_ENDIAN ? nwords - i - 1 : i);
+ /* Word number in TARGET to use. */
+ int wordnum = (WORDS_BIG_ENDIAN
+ ? GET_MODE_SIZE (GET_MODE (target)) / UNITS_PER_WORD - i - 1
+ : i);
+ /* Offset from start of field in OP0. */
int bit_offset = (WORDS_BIG_ENDIAN
? MAX (0, bitsize - (i + 1) * BITS_PER_WORD)
: i * BITS_PER_WORD);
@@ -929,7 +937,24 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
}
if (unsignedp)
- return target;
+ {
+ /* Unless we've filled TARGET, the upper regs in a multi-reg value
+ need to be zero'd out. */
+ if (GET_MODE_SIZE (GET_MODE (target)) > nwords * UNITS_PER_WORD)
+ {
+ int i,total_words;
+
+ total_words = GET_MODE_SIZE (GET_MODE (target)) / UNITS_PER_WORD;
+ for (i = nwords; i < total_words; i++)
+ {
+ int wordnum = WORDS_BIG_ENDIAN ? total_words - i - 1 : i;
+ rtx target_part = operand_subword (target, wordnum, 1, VOIDmode);
+ emit_move_insn (target_part, const0_rtx);
+ }
+ }
+ return target;
+ }
+
/* Signed bit field: sign-extend with two arithmetic shifts. */
target = expand_shift (LSHIFT_EXPR, mode, target,
build_int_2 (GET_MODE_BITSIZE (mode) - bitsize, 0),
@@ -1424,7 +1449,8 @@ extract_fixed_bit_field (tmode, op0, offset, bitsize, bitpos,
/* Return a constant integer (CONST_INT or CONST_DOUBLE) mask value
of mode MODE with BITSIZE ones followed by BITPOS zeros, or the
complement of that if COMPLEMENT. The mask is truncated if
- necessary to the width of mode MODE. */
+ necessary to the width of mode MODE. The mask is zero-extended if
+ BITSIZE+BITPOS is too small for MODE. */
static rtx
mask_rtx (mode, bitpos, bitsize, complement)