aboutsummaryrefslogtreecommitdiff
path: root/gcc/expr.c
diff options
context:
space:
mode:
authorKazu Hirata <kazu@cs.umass.edu>2005-03-02 16:04:50 +0000
committerKazu Hirata <kazu@gcc.gnu.org>2005-03-02 16:04:50 +0000
commit92fb2d32d5e8ff33855ab277581cd088c36cffa5 (patch)
tree9dcbe9e572ba553267b04d23cba26ed6a5d2503f /gcc/expr.c
parent613c5cd0c61e7a93867db827b8570af26b2fe002 (diff)
downloadgcc-92fb2d32d5e8ff33855ab277581cd088c36cffa5.zip
gcc-92fb2d32d5e8ff33855ab277581cd088c36cffa5.tar.gz
gcc-92fb2d32d5e8ff33855ab277581cd088c36cffa5.tar.bz2
PR middle-end/18029 and PR middle-end/18030
PR middle-end/18029 and PR middle-end/18030 * expr.c (optimize_bitfield_assignment_op): Add a special case to handle BIT_IOR_EXPR and BIT_XOR_EXPR. From-SVN: r95782
Diffstat (limited to 'gcc/expr.c')
-rw-r--r--gcc/expr.c35
1 files changed, 35 insertions, 0 deletions
diff --git a/gcc/expr.c b/gcc/expr.c
index ab7cf93..c2c9ffe 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -3755,6 +3755,41 @@ optimize_bitfield_assignment_op (unsigned HOST_WIDE_INT bitsize,
emit_move_insn (str_rtx, result);
return true;
+ case BIT_IOR_EXPR:
+ case BIT_XOR_EXPR:
+ if (TREE_CODE (op1) != INTEGER_CST)
+ break;
+ value = expand_expr (op1, NULL_RTX, GET_MODE (str_rtx), 0);
+ value = convert_modes (GET_MODE (str_rtx),
+ TYPE_MODE (TREE_TYPE (op1)), value,
+ TYPE_UNSIGNED (TREE_TYPE (op1)));
+
+ /* We may be accessing data outside the field, which means
+ we can alias adjacent data. */
+ if (MEM_P (str_rtx))
+ {
+ str_rtx = shallow_copy_rtx (str_rtx);
+ set_mem_alias_set (str_rtx, 0);
+ set_mem_expr (str_rtx, 0);
+ }
+
+ binop = TREE_CODE (src) == BIT_IOR_EXPR ? ior_optab : xor_optab;
+ if (bitpos + bitsize != GET_MODE_BITSIZE (GET_MODE (str_rtx)))
+ {
+ rtx mask = GEN_INT (((unsigned HOST_WIDE_INT) 1 << bitsize)
+ - 1);
+ value = expand_and (GET_MODE (str_rtx), value, mask,
+ NULL_RTX);
+ }
+ value = expand_shift (LSHIFT_EXPR, GET_MODE (str_rtx), value,
+ build_int_cst (NULL_TREE, bitpos),
+ NULL_RTX, 1);
+ result = expand_binop (GET_MODE (str_rtx), binop, str_rtx,
+ value, str_rtx, 1, OPTAB_WIDEN);
+ if (result != str_rtx)
+ emit_move_insn (str_rtx, result);
+ return true;
+
default:
break;
}