https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94715
--- Comment #4 from Jakub Jelinek <jakub at gcc dot gnu.org> --- The GIMPLE transformation is correct and should stay as is. User could have written int t = x * x; return t; instead. What you are asking for is a new RTL optimization somewhere (dunno if in expander, or where else), where e.g. using value ranges from the GIMPLE opts the middle-end? sees that both sign and zero extension do what needs to be performed because the value doesn't have msb set, and uses costs to decide which one is faster. # RANGE [0, 2147483647] NONZERO 2147483645 t_2 = x_1(D) * x_1(D); # RANGE [0, 2147483647] NONZERO 2147483645 _3 = (long long unsigned int) t_2; So, in this case it could be an optimization done in expand_expr_real_2 in the CASE_CONVERT: case after the else if (modifier == EXPAND_INITIALIZER) case or so.