https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95396

--- Comment #7 from Richard Biener <rguenth at gcc dot gnu.org> ---
(In reply to Richard Biener from comment #6)
> One odd thing is that for unsigned char _3 we get via
> 
>                 wide_int var_min, var_max;
>                 value_range_kind vr_type = get_range_info (tmp_var, &var_min,
>                                                            &var_max);
> 
> [241, 255]
> 
> the add of 15 then overflows for both min and max and thus we happily accept
> the result but compute the difference signed (in widest_int):
> 
>                 /* Calculate (ssizetype) OP0 - (ssizetype) TMP_VAR.  */
>                 widest_int diff = (widest_int::from (op0_min, sgn)
>                                    - widest_int::from (var_min, sgn));
>                 var0 = tmp_var;
>                 *off = wide_int_to_tree (ssizetype, diff);
> 
> which then results in 0-241 == -241.
> 
> To me it looks like we should instead do
> 
>                 /* Calculate (ssizetype) (OP0 - TMP_VAR).  */
>                 widest_int diff = widest_int::from (op0_min - var_min, sgn);
> 
> which fixes this particular testcase.

Or alternatively

                widest_int diff = wi::ext (widest_int::from (op0_min, sgn)
                                           - widest_int::from (var_min, sgn),
                                           TYPE_PRECISION (type),
                                           TYPE_SIGN (type));

which maybe more highlights the underlying issue (failing zero-extension
for the sign-changing conversion)?

I don't expect any fallout of either patch possibly due to bad test
coverage so extra thoughts welcome.

Reply via email to