Attached is what I have for carry_backpropagate . The utility of special handling for SS_ASHIFT / US_ASHIFT seems somewhat marginal.
I suspect it'd be more useful to add handling of LSHIFTRT and ASHIFTRT . Some ports do a lot of static shifting.
commit ed47c3d0d38f85c9b4e22bdbd079e0665465ef9c Author: Joern Rennecke <joern.renne...@embecosm.com> Date: Wed Nov 29 18:46:06 2023 +0000 * ext-dce.c: Fixes for carry handling. * ext-dce.c (safe_for_live_propagation): Handle MINUS. (ext_dce_process_uses): Break out carry handling into .. (carry_backpropagate): This new function. Better handling of ASHIFT. Add handling of SMUL_HIGHPART, UMUL_HIGHPART, SIGN_EXTEND, SS_ASHIFT and US_ASHIFT. diff --git a/gcc/ext-dce.cc b/gcc/ext-dce.cc index 590656f72c7..2a4508181a1 100644 --- a/gcc/ext-dce.cc +++ b/gcc/ext-dce.cc @@ -83,6 +83,7 @@ safe_for_live_propagation (rtx_code code) case SIGN_EXTEND: case TRUNCATE: case PLUS: + case MINUS: case MULT: case SMUL_HIGHPART: case UMUL_HIGHPART: @@ -365,6 +366,67 @@ binop_implies_op2_fully_live (rtx_code code) } } +/* X, with code CODE, is an operation for which +safe_for_live_propagation holds true, + and bits set in MASK are live in the result. Compute a make of (potentially) + live bits in the non-constant inputs. In case of +binop_implies_op2_fully_live + (e.g. shifts), the computed mask may exclusively pertain to the +first operand. */ + +HOST_WIDE_INT +carry_backpropagate (HOST_WIDE_INT mask, enum rtx_code code, rtx x) +{ + enum machine_mode mode = GET_MODE (x); + HOST_WIDE_INT mmask = GET_MODE_MASK (mode); + switch (code) + { + case ASHIFT: + if (CONSTANT_P (XEXP (x, 1)) + && known_lt (UINTVAL (XEXP (x, 1)), GET_MODE_BITSIZE (mode))) + return mask >> INTVAL (XEXP (x, 1)); + /* Fall through. */ + case PLUS: case MINUS: + case MULT: + return mask ? ((2ULL << floor_log2 (mask)) - 1) : 0; + case SMUL_HIGHPART: case UMUL_HIGHPART: + if (!mask || XEXP (x, 1) == const0_rtx) + return 0; + if (CONSTANT_P (XEXP (x, 1))) + { + if (pow2p_hwi (INTVAL (XEXP (x, 1)))) + return mmask & (mask << (GET_MODE_BITSIZE (mode).to_constant () + - exact_log2 (INTVAL (XEXP (x, 1))))); + + int bits = (2 * GET_MODE_BITSIZE (mode).to_constant () + - clz_hwi (mask) - ctz_hwi (INTVAL (XEXP (x, 1)))); + if (bits < GET_MODE_BITSIZE (mode).to_constant ()) + return (1ULL << bits) - 1; + } + return mmask; + case SIGN_EXTEND: + if (mask & ~mmask) + mask |= 1ULL << (GET_MODE_BITSIZE (mode).to_constant () - 1); + return mask; + + /* We propagate for the shifted operand, but not the shift + count. The count is handled specially. */ + case SS_ASHIFT: + case US_ASHIFT: + if (!mask || XEXP (x, 1) == const0_rtx) + return 0; + if (CONSTANT_P (XEXP (x, 1)) + && UINTVAL (XEXP (x, 1)) < GET_MODE_BITSIZE (mode).to_constant ()) + { + return ((mmask & ~((unsigned HOST_WIDE_INT)mmask + >> (INTVAL (XEXP (x, 1)) + (code == SS_ASHIFT)))) + | (mask >> INTVAL (XEXP (x, 1)))); + } + return mmask; + default: + return mask; + } +} /* Process uses in INSN contained in OBJ. Set appropriate bits in LIVENOW for any chunks of pseudos that become live, potentially filtering using bits from LIVE_TMP. @@ -480,11 +542,7 @@ ext_dce_process_uses (rtx_insn *insn, rtx obj, bitmap livenow, sure everything that should get marked as live is marked from here onward. */ - /* ?!? What is the point of this adjustment to DST_MASK? */ - if (code == PLUS || code == MINUS - || code == MULT || code == ASHIFT) - dst_mask - = dst_mask ? ((2ULL << floor_log2 (dst_mask)) - 1) : 0; + dst_mask = carry_backpropagate (dst_mask, code, src); /* We will handle the other operand of a binary operator at the bottom of the loop by resetting Y. */