From af508edd0a24fde29a7f879577b2ad2498d5123d Mon Sep 17 00:00:00 2001 From: Richard Kenner Date: Sat, 26 Jun 1993 11:06:01 -0400 Subject: [PATCH] (do_store_flag): When computing via a shift, allow for an inner RSHIFT_EXPR in BITNUM. (do_store_flag): When computing via a shift, allow for an inner RSHIFT_EXPR in BITNUM. Sometimes do the operations as signed. From-SVN: r4747 --- gcc/expr.c | 43 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/gcc/expr.c b/gcc/expr.c index 144eb637f2e..89be8598eb7 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -7864,30 +7864,57 @@ do_store_flag (exp, target, mode, only_cheap) && integer_pow2p (TREE_OPERAND (arg0, 1)) && TYPE_PRECISION (type) <= HOST_BITS_PER_WIDE_INT) { + tree inner = TREE_OPERAND (arg0, 0); int bitnum = exact_log2 (INTVAL (expand_expr (TREE_OPERAND (arg0, 1), NULL_RTX, VOIDmode, 0))); + int ops_unsignedp; + + /* If INNER is a right shift of a constant and it plus BITNUM does + not overflow, adjust BITNUM and INNER. */ + + if (TREE_CODE (inner) == RSHIFT_EXPR + && TREE_CODE (TREE_OPERAND (inner, 1)) == INTEGER_CST + && TREE_INT_CST_HIGH (TREE_OPERAND (inner, 1)) == 0 + && (bitnum + TREE_INT_CST_LOW (TREE_OPERAND (inner, 1)) + < TYPE_PRECISION (type))) + { + bitnum +=TREE_INT_CST_LOW (TREE_OPERAND (inner, 1)); + inner = TREE_OPERAND (inner, 0); + } + + /* If we are going to be able to omit the AND below, we must do our + operations as unsigned. If we must use the AND, we have a choice. + Normally unsigned is faster, but for some machines signed is. */ + ops_unsignedp = (bitnum == TYPE_PRECISION (type) - 1 ? 1 +#ifdef BYTE_LOADS_SIGN_EXTEND + : 0 +#else + : 1 +#endif + ); if (subtarget == 0 || GET_CODE (subtarget) != REG || GET_MODE (subtarget) != operand_mode - || ! safe_from_p (subtarget, TREE_OPERAND (arg0, 0))) + || ! safe_from_p (subtarget, inner)) subtarget = 0; - op0 = expand_expr (TREE_OPERAND (arg0, 0), subtarget, VOIDmode, 0); + op0 = expand_expr (inner, subtarget, VOIDmode, 0); if (bitnum != 0) op0 = expand_shift (RSHIFT_EXPR, GET_MODE (op0), op0, - size_int (bitnum), target, 1); + size_int (bitnum), target, ops_unsignedp); if (GET_MODE (op0) != mode) - op0 = convert_to_mode (mode, op0, 1); + op0 = convert_to_mode (mode, op0, ops_unsignedp); + + if ((code == EQ && ! invert) || (code == NE && invert)) + op0 = expand_binop (mode, xor_optab, op0, const1_rtx, target, + ops_unsignedp, OPTAB_LIB_WIDEN); + /* Put the AND last so it can combine with more things. */ if (bitnum != TYPE_PRECISION (type) - 1) op0 = expand_and (op0, const1_rtx, target); - if ((code == EQ && ! invert) || (code == NE && invert)) - op0 = expand_binop (mode, xor_optab, op0, const1_rtx, target, 0, - OPTAB_LIB_WIDEN); - return op0; } -- 2.30.2