If we see a promoted subreg and TRULY_NOOP_TRUNCATION says the truncation is not a noop, then all bits of the inner reg are live. We cannot reduce the live mask to that of the mode of the subreg.
gcc/ChangeLog: PR rtl-optimization/120050 * ext-dce.cc (ext_dce_process_uses): Break early if a SUBREG in rhs is promoted and the truncation from the inner mode to the outer mode is not a noop when handling SETs. --- Bootstrapped on mips64el-linux-gnuabi64. Ok for trunk? gcc/ext-dce.cc | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/gcc/ext-dce.cc b/gcc/ext-dce.cc index a0343950141..3b21e68b90c 100644 --- a/gcc/ext-dce.cc +++ b/gcc/ext-dce.cc @@ -35,6 +35,7 @@ along with GCC; see the file COPYING3. If not see #include "print-rtl.h" #include "dbgcnt.h" #include "diagnostic-core.h" +#include "target.h" /* These should probably move into a C++ class. */ static vec<bitmap_head> livein; @@ -764,13 +765,20 @@ ext_dce_process_uses (rtx_insn *insn, rtx obj, We don't want to mark those bits live unnecessarily as that inhibits extension elimination in important cases such as those in Coremark. So we need that - outer code. */ + outer code. + + But if !TRULY_NOOP_TRUNCATION_MODES_P, those bits + may be actually alive with any promoted subreg + regardless of the outer code. See PR 120050. */ if (!REG_P (SUBREG_REG (y)) || (SUBREG_PROMOTED_VAR_P (y) && ((GET_CODE (SET_SRC (x)) == SIGN_EXTEND && SUBREG_PROMOTED_SIGNED_P (y)) || (GET_CODE (SET_SRC (x)) == ZERO_EXTEND - && SUBREG_PROMOTED_UNSIGNED_P (y))))) + && SUBREG_PROMOTED_UNSIGNED_P (y)) + || !TRULY_NOOP_TRUNCATION_MODES_P ( + GET_MODE (y), + GET_MODE (SUBREG_REG (y)))))) break; bit = subreg_lsb (y).to_constant (); -- 2.49.0