> 2020-12-10  Jakub Jelinek  <ja...@redhat.com>
> 
>       PR middle-end/98190
>       * expr.c (expand_assignment): If to_rtx is a promoted SUBREG,
>       ensure sign or zero extension when the most significant bit has
>       been overwritten, either through use of store_expr or by extending
>       manually.
> 
>       * gcc.dg/pr98190.c: New test.
> 
> --- gcc/expr.c.jj     2020-12-09 23:50:41.385776978 +0100
> +++ gcc/expr.c        2020-12-10 09:35:56.231058928 +0100
> @@ -5451,6 +5451,43 @@ expand_assignment (tree to, tree from, b
>                                              mode1, to_rtx, 
to, from,
>                                              reversep))
>           result = NULL;
> +       else if (SUBREG_P (to_rtx)
> +                && SUBREG_PROMOTED_VAR_P (to_rtx))
> +         {
> +           /* If to_rtx is a promoted subreg, we need to zero or sign
> +              extend the value afterwards.  */
> +           if (TREE_CODE (to) == MEM_REF
> +               && !REF_REVERSE_STORAGE_ORDER (to)
> +               && known_eq (bitpos, 0)
> +               && known_eq (bitsize, GET_MODE_BITSIZE (GET_MODE 
(to_rtx))))
> +             result = store_expr (from, to_rtx, 0, nontemporal, 
false);
> +           else
> +             {
> +               rtx to_rtx1 = to_rtx;
> +               /* Optimize by checking if the overwritten bits
> +                  include the most significant bit.  */
> +               if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN
> +                   || (BYTES_BIG_ENDIAN && known_eq (bitpos, 0))
> +                   || (!BYTES_BIG_ENDIAN
> +                       && known_eq (bitpos + bitsize,
> +                                    GET_MODE_BITSIZE (GET_MODE 
(to_rtx)))))
> +                 to_rtx1 = lowpart_subreg (subreg_unpromoted_mode 
(to_rtx),
> +                                           SUBREG_REG 
(to_rtx),
> +                                           
subreg_promoted_mode (to_rtx));
> +               result = store_field (to_rtx1, bitsize, bitpos,
> +                                     bitregion_start, 
bitregion_end,
> +                                     mode1, from, 
get_alias_set (to),
> +                                     nontemporal, reversep);
> +               if (to_rtx1 != to_rtx)
> +                 {
> +                   to_rtx1
> +                     = convert_to_mode (subreg_promoted_mode 
(to_rtx),
> +                                        to_rtx1,
> +                                        SUBREG_PROMOTED_SIGN 
(to_rtx));
> +                   emit_move_insn (SUBREG_REG (to_rtx), to_rtx1);
> +                 }
> +             }
> +         }
>         else
>           result = store_field (to_rtx, bitsize, bitpos,
>                                 bitregion_start, bitregion_end,

Are you sure that the optimization is worth the hassle (and maybe the risk, 
i.e. can't store_field clobber the entire field)?

Any particular reason not to use the canonical idiom at the end, i.e. just

          convert_move (SUBREG_REG (to_rtx), to_rtx1,
                     SUBREG_PROMOTED_SIGN (to_rtx));

-- 
Eric Botcazou


Reply via email to