rtx src = SET_SRC (set);
rtx inner = XEXP (src, 0);
+ /* For sign-extending loads from memory, try to replace with a
+ zero-extending load when the upper bits are dead. E.g. on RISC-V
+ this turns lh+zext.h into just lhu. */
+ if (MEM_P (inner) && GET_CODE (src) == SIGN_EXTEND)
+ {
+ if (dump_file)
+ {
+ fprintf (dump_file, "Processing insn:\n");
+ dump_insn_slim (dump_file, insn);
+ fprintf (dump_file, "Trying to narrow sign_extend to zero_extend:\n");
+ print_rtl_single (dump_file, SET_SRC (set));
+ }
+
+ if (!dbg_cnt (::ext_dce))
+ {
+ if (dump_file)
+ fprintf (dump_file, "Rejected due to debug counter.\n");
+ return;
+ }
+
+ rtx new_pattern = gen_rtx_ZERO_EXTEND (GET_MODE (src), inner);
+ int ok = validate_change (insn, &SET_SRC (set), new_pattern, false);
+
+ rtx x = SET_DEST (set);
+ while (SUBREG_P (x) || GET_CODE (x) == ZERO_EXTRACT)
+ x = XEXP (x, 0);
+
+ gcc_assert (REG_P (x));
+ if (ok)
+ {
+ bitmap_set_bit (changed_pseudos, REGNO (x));
+ remove_reg_equal_equiv_notes (insn, false);
+ }
+
+ if (dump_file)
+ {
+ if (ok)
+ fprintf (dump_file, "Successfully transformed to:\n");
+ else
+ fprintf (dump_file, "Failed transformation to:\n");
+ print_rtl_single (dump_file, new_pattern);
+ fprintf (dump_file, "\n");
+ }
+ return;
+ }
+
/* Avoid (subreg (mem)) and other constructs which may be valid RTL, but
not useful for this optimization. */
if (!(REG_P (inner) || (SUBREG_P (inner) && REG_P (SUBREG_REG (inner)))))
--- /dev/null
+/* Verify that ext-dce narrows sign-extending loads to zero-extending loads
+ when the upper bits are dead. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+/*
+** test_half:
+** ...
+** ldrh .*
+** ...
+*/
+/* Positive: halfword load-modify-store — sign bits are dead. */
+void
+test_half (signed short *p)
+{
+ *p = (*p & 0xff00) | (0x00ff & (*p >> 8));
+}
+
+/*
+** test_byte:
+** ...
+** ldrb .*
+** ...
+*/
+/* Positive: byte load-modify-store — sign bits are dead. */
+void
+test_byte (signed char *p)
+{
+ *p = (*p & 0xf0) | (0x0f & (*p >> 4));
+}
+
+/*
+** test_half_sign_needed:
+** ...
+** ldrsb .*
+** ...
+*/
+/* Negative: arithmetic right shift needs the sign extension. */
+int
+test_half_sign_needed (signed short *p)
+{
+ return *p >> 8;
+}
+
+/*
+** test_half_compare:
+** ...
+** ldrsh .*
+** ...
+*/
+/* Negative: sign-dependent comparison. */
+int
+test_half_compare (signed short *p)
+{
+ return *p < 0;
+}
+
--- /dev/null
+/* Verify ext-dce for word loads on RV64: lw sign-extends to 64 bits,
+ so when the upper 32 bits are dead lw should be narrowed to lwu. */
+/* { dg-do compile } */
+/* { dg-require-effective-target rv64 } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -O2" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+/*
+** test_word:
+** ...
+** lwu .*
+** ...
+*/
+/* Positive: word load-modify-store — upper 32 bits are dead. */
+void
+test_word (signed int *p)
+{
+ *p = (*p & 0xffff0000) | (0x0000ffff & ((unsigned int)*p >> 16));
+}
+
+/*
+** test_word_sign_needed:
+** ...
+** lw .*
+** ...
+*/
+/* Negative: return value is long — sign extension is needed. */
+long
+test_word_sign_needed (signed int *p)
+{
+ return *p;
+}
+
--- /dev/null
+/* Verify that ext-dce narrows sign-extending loads to zero-extending loads
+ when the upper bits are dead. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+/*
+** test_half:
+** ...
+** lhu .*
+** ...
+*/
+/* Positive: halfword load-modify-store — sign bits are dead. */
+void
+test_half (signed short *p)
+{
+ *p = (*p & 0xff00) | (0x00ff & (*p >> 8));
+}
+
+/*
+** test_byte:
+** ...
+** lbu .*
+** ...
+*/
+/* Positive: byte load-modify-store — sign bits are dead. */
+void
+test_byte (signed char *p)
+{
+ *p = (*p & 0xf0) | (0x0f & (*p >> 4));
+}
+
+/*
+** test_half_sign_needed:
+** ...
+** lh .*
+** ...
+*/
+/* Negative: arithmetic right shift needs the sign extension. */
+int
+test_half_sign_needed (signed short *p)
+{
+ return *p >> 8;
+}
+
+/*
+** test_half_compare:
+** ...
+** lh .*
+** ...
+*/
+/* Negative: sign-dependent comparison. */
+int
+test_half_compare (signed short *p)
+{
+ return *p < 0;
+}
+