aboutsummaryrefslogtreecommitdiff
path: root/gcc/expmed.c
diff options
context:
space:
mode:
authorJim Wilson <wilson@gcc.gnu.org>1994-02-27 16:55:33 -0800
committerJim Wilson <wilson@gcc.gnu.org>1994-02-27 16:55:33 -0800
commit5f57dff07ba01651525283483b6ffc1ff59dfa59 (patch)
treefb59a6276e5779219ed40a789de47de0988a93bf /gcc/expmed.c
parent81284a6ad220981f2d6a0e13ce3dade55c10cab8 (diff)
downloadgcc-5f57dff07ba01651525283483b6ffc1ff59dfa59.zip
gcc-5f57dff07ba01651525283483b6ffc1ff59dfa59.tar.gz
gcc-5f57dff07ba01651525283483b6ffc1ff59dfa59.tar.bz2
(store_split_bit_field): If OP0 is a SUBREG, then compute WORD from the base register, instead of from the SUBREG.
(store_split_bit_field): If OP0 is a SUBREG, then compute WORD from the base register, instead of from the SUBREG. (extract_split_bit_field): Likewise. (extract_bit_field): Sign-extend multiword bitfield if necessary. From-SVN: r6668
Diffstat (limited to 'gcc/expmed.c')
-rw-r--r--gcc/expmed.c40
1 files changed, 35 insertions, 5 deletions
diff --git a/gcc/expmed.c b/gcc/expmed.c
index 5a06dbf..1d5d75e 100644
--- a/gcc/expmed.c
+++ b/gcc/expmed.c
@@ -757,8 +757,19 @@ store_split_bit_field (op0, bitsize, bitpos, value, align)
#endif
/* 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)
+
+ When handling multiword bitfields, extract_bit_field may pass
+ down a word_mode SUBREG of a larger REG for a bitfield that actually
+ crosses a word boundary. Thus, for a SUBREG, we must find
+ the current word starting from the base register. */
+ if (GET_CODE (op0) == SUBREG)
+ {
+ word = operand_subword (SUBREG_REG (op0),
+ SUBREG_WORD (op0) + offset, 1,
+ GET_MODE (SUBREG_REG (op0)));
+ offset = 0;
+ }
+ else if (GET_CODE (op0) == REG)
{
word = operand_subword (op0, offset, 1, GET_MODE (op0));
offset = 0;
@@ -917,7 +928,15 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
emit_move_insn (target_part, result_part);
}
- return target;
+ if (unsignedp)
+ 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),
+ NULL_RTX, 0);
+ return expand_shift (RSHIFT_EXPR, mode, target,
+ build_int_2 (GET_MODE_BITSIZE (mode) - bitsize, 0),
+ NULL_RTX, 0);
}
/* From here on we know the desired field is smaller than a word
@@ -1505,8 +1524,19 @@ extract_split_bit_field (op0, bitsize, bitpos, unsignedp, align)
thissize = MIN (thissize, unit - thispos);
/* 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)
+
+ When handling multiword bitfields, extract_bit_field may pass
+ down a word_mode SUBREG of a larger REG for a bitfield that actually
+ crosses a word boundary. Thus, for a SUBREG, we must find
+ the current word starting from the base register. */
+ if (GET_CODE (op0) == SUBREG)
+ {
+ word = operand_subword_force (SUBREG_REG (op0),
+ SUBREG_WORD (op0) + offset,
+ GET_MODE (SUBREG_REG (op0)));
+ offset = 0;
+ }
+ else if (GET_CODE (op0) == REG)
{
word = operand_subword_force (op0, offset, GET_MODE (op0));
offset = 0;