}
}
+/* SUBREG_PROMOTED_VAR_P is set by the gimple->rtl optimizers and
+ is usually helpful. However, in some cases setting the value when
+ it not strictly needed can cause this pass to miss optimizations.
+
+ Specifically consider (set (mem) (subreg (reg))). If set in that
+ case it will cause more bit groups to be live for REG than would
+ be strictly necessary which in turn can inhibit extension removal.
+
+ So do a pass over the IL wiping the SUBREG_PROMOTED_VAR_P when it
+ is obviously not needed. */
+
+static void
+maybe_clear_subreg_promoted_p (void)
+{
+ for (rtx_insn *insn = get_insns(); insn; insn = NEXT_INSN (insn))
+ {
+ if (!NONDEBUG_INSN_P (insn))
+ continue;
+
+ rtx set = single_set (insn);
+ if (!set)
+ continue;
+
+ /* There may be other cases where we should clear, but for
+ now, this is the only known case where it causes problems. */
+ if (MEM_P (SET_DEST (set)) && SUBREG_P (SET_SRC (set))
+ && GET_MODE (SET_DEST (set)) <= GET_MODE (SUBREG_REG (SET_SRC (set))))
+ SUBREG_PROMOTED_VAR_P (SET_SRC (set)) = 0;
+ }
+}
+
+
/* We optimize away sign/zero extensions in this pass and replace
them with SUBREGs indicating certain bits are don't cares.
void
ext_dce_execute (void)
{
+ /* Some settings of SUBREG_PROMOTED_VAR_P are actively harmful
+ to this pass. Clear it for those cases. */
+ maybe_clear_subreg_promoted_p ();
df_analyze ();
ext_dce_init ();
--- /dev/null
+/* { dg-options "-O2 -fdump-rtl-ext_dce" } */
+typedef unsigned char __uint8_t;
+typedef unsigned int __uint32_t;
+typedef __uint8_t uint8_t;
+typedef __uint32_t uint32_t;
+static inline void
+unaligned_write32le(uint8_t *buf, uint32_t num)
+{
+ buf[0] = num;
+ buf[1] = num >> 8;
+ buf[2] = num >> 16;
+ buf[3] = num >> 24;
+ return;
+}
+typedef struct {
+ uint32_t dict_size;
+} lzma_options_lzma;
+typedef void lzma_coder;
+typedef struct lzma_next_coder_s lzma_next_coder;
+struct lzma_next_coder_s {
+ lzma_coder *coder;
+};
+struct lzma_coder_s {
+ uint8_t header[(1 + 4 + 8)];
+};
+
+void
+alone_encoder_init(lzma_next_coder *next, const lzma_options_lzma *options)
+{
+ uint32_t d = options->dict_size - 1;
+ d |= d >> 2;
+#if 0
+ d |= d >> 3;
+ d |= d >> 4;
+ d |= d >> 8;
+ d |= d >> 16;
+#endif
+ if (d != (4294967295U))
+ ++d;
+ unaligned_write32le(((struct lzma_coder_s*)next->coder)->header + 1, d);
+}
+
+/* { dg-final { scan-rtl-dump "Successfully transformed to:" "ext_dce" } } */
+