[Bug tree-optimization/104547] std::vector::resize(v.size() - n) produces poor code

amacleod at redhat dot com gcc-bugzilla@gcc.gnu.org
Tue Feb 15 15:27:17 GMT 2022


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

--- Comment #7 from Andrew Macleod <amacleod at redhat dot com> ---
Created attachment 52447
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=52447&action=edit
proposed patch

(In reply to Jakub Jelinek from comment #5)
> If you mean with -O3 on the
> #include <vector>
> 
> void shrink(std::vector<int>& v, unsigned n) {
>     if (v.size() < n)
>       __builtin_unreachable();
>     v.resize(v.size() - n);
> }
> testcase (with -O2 _M_default_append isn't nlined), then I think it is
> something that ideally ranger's symbolic handling should figure out but
> doesn't.
> We have:
>   long unsigned int _1;
> ...
>   long unsigned int _11;
> ...
>   if (_1 > _11)
>     goto <bb 3>; [0.00%]
>   else
>     goto <bb 4>; [100.00%]
>   
>   <bb 3> [count: 0]:
>   __builtin_unreachable ();
>   
>   <bb 4> [local count: 1073741824]:
>   # RANGE ~[2305843009213693952, 16140901060200890368]
>   _2 = _11 - _1;
>   if (_2 > _11)
> and we don't figure out that _2 > _11 is always false, because we earlier
> assert that _1 <= _11 and so _11 - _1 will not wrap around and so the result
> _2 <= _11.

Relational : (_1 <= _11)
    <bb 4> [local count: 1073741824]:
    _2 = _11 - _1;
    if (_2 > _11)
      goto <bb 5>; [33.00%]
    else
      goto <bb 6>; [67.00%]

Looks like we know _1 is <= _11, but what seems to be missing is the extra
relation that _2 > _11 as a result.

normally we'd handle this by providing operator_minus::lhs_op1_relation()
routine, but unfortunately, it does not currently take a relation between op1
and op2 like the corresponding fold does.. it should be trivial to add it
however. 

The attached patch does the basics...  adds the parameter and provides a very
simple operator_minus::lhs_op1_relation () which then achieves the goal of the
PR. It hasn't been bootstrapped or anything.

I didn't try to flush out anything else, or make any enhancements because I
don't trust myself at this late stage to get it right :-) Feel free to work
with it if you want.

ie, I don't even look at the ranges.. if op1 >= op2, we return LHS <= op1.  We
could also check if the range of op2 does not contain 0, then we could return
LSH < OP1.  There is probably some sign checking that could be done too. 

There is also  the routine fold uses (minus_op1_op2_relation_effect) which
could possibly be leveraged as well, but I don't want to delve into that

Note that this will affect all minus operations everywhere...  for instance,
this patch ends up enabling a much earlier threading pass to eliminate the
branch.. so it never makes it to VRP2.

I also didn't implement lhs_op2 relation.. again, I don't trust myself to get
it right.
So I can either package this up and submit it, or someone more trustworthy can
take it an run with it and add whatever tweaks you feel are safe.


More information about the Gcc-bugs mailing list