This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: std::vector move assign patch


On Tue, 25 Apr 2017, Jonathan Wakely wrote:

That's only 5 more memory operations. If I tweak vector swapping to avoid calling swap on each member (which drops type-based aliasing information, that was the topic of PR64601)

I didn't really understand the discussion in the PR. I find that's
true of most TBAA discussions.

std::swap(T& x, T& y) is hard to optimise because we don't know that
the dynamic type of the thing at &x is the same type as T?

std::swap<int*> only knows that it is dealing with pointers to integers, so _M_start from one vector might be in the same location as _M_finish from some other vector...

When I access __x._M_start directly, I am accessing some part of a _Vector_impl, and 2 _Vector_impl can only be the same or disjoint, they cannot partially overlap.

I see. I'm surprised that after the std::swap calls get inlined, so
that the references can be "seen through", the pessimisation is still
present.

(this is my understanding of how compilers handle TBAA)

The only things that carry information are the declaration of an object, and accesses (read/write). Pointers and references are meaningless until the object is accessed, they are just a fancy way to do pointer arithmetic, and the way the object is accessed carries the whole information. If I have a reference p to std::pair<int,int>, p.first=42 or x=p.first access the first element of a pair, while *&p.first=42 or x=*&p.first are only accesses to an int. p.first and q.second cannot alias, while *&p.first and *&q.second can.

In other words
illegal: ((std::pair<int,int>*)&p.second)->first=2
allowed: *(int*)&((std::pair<int,int>*)&p.second)->first=2
because there is no actual access through the "wrong" pointers (I added a redundant cast to int* to try and clarify the difference).

(actually, gcc wrongly optimizes *&x to x so you need to use an intermediate variable to notice this: auto y=&x; ... *y ... while clang is stricter)

I think this is horrible but that's not a fight I feel capable of leading.

If what I said is too hard to understand, it is fine to ignore. And if it is wrong, I'll be happy to learn that :-)

By the way, do we have a policy on writing if(p)delete p; vs directly delete p; which does nothing for p==0? There are cases where the extra shortcut is a nice optimization, others where it is redundant work. At -Os, the middle-end could optimize if(p)free(p) to free(p) in the future.

No official policy. I always consider the if (p) to be redundant
noise, but that's based on readability and correctness, not
performance.

I was going to say we have that in std::vector's destructor, but allocators do not have the same property as free/delete, deallocate can only be called with something allocate returned, not 0. So we don't have a choice.

--
Marc Glisse


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]