Optimizing away deletion of null pointers with g++
Richard Biener
richard.guenther@gmail.com
Wed Aug 16 11:31:00 GMT 2017
On Wed, Aug 16, 2017 at 12:09 PM, Daniel Langr <daniel.langr@gmail.com> wrote:
> When compiling the following code:
>
> int* ptr = nullptr;
> delete ptr;
>
> GCC 7.1 on x86_64 generates a delete-operator-related call instruction in
> the resulting program with both -O2 and -O3 optimization flags. This is a
> nonsense piece of code, indeed, but imagine a class that has an owning raw
> pointer (please, don't tell me to use unique_ptr, there are such classes in
> the real world). Then, this class needs to call delete in its move
> assignment operator and destructor:
>
> class X {
> T* ptr_;
> public:
> X() ptr_(nullptr) { }
> X& operator=(X&& rhs) {
> delete ptr_;
> ptr_ = rhs.ptr_;
> rhs.ptr_ = nullptr;
> return *this;
> }
> ~X() { delete ptr_; }
> ...
> };
> Invoking std::swap with objects of class X then yields deletion of null
> pointer 3 times (2 times within move assignment operator and once within
> destructor). Since GCC doesn't optimize out these null-pointer deletions and
> generate corresponding call instructions, whole swapping has some
> performance penalty.
>
> I found out that if I change 'delete ptr_;' to 'if (ptr_) delete ptr_;',
> then no call instructions are generated. So, I did a benchmark that sorted
> 100M randomly-shuffled objects of class X (where T was int) with std::sort.
> Here are measured sorting times:
>
> 1) 40.8 seconds with plain 'delete ptr_;',
> 2) 31.5 seconds with 'if (ptr_) delete ptr_;',
> 3) 31.3 seconds with additional custom swap free function for class X.
>
> This is quite a big performance difference between first two cases. Wouldn't
> be nice if g++ was able to optimize out deletion of null pointers? I guess
> in cases such as above mentioned one the null pointers can be recognized by
> static analysis. (As far as I know omitting delete operator calls is
> standard-compliant. Both Clang and Intel compilers did this in my tests.)
I suppose one needs to mark operator delete specially, like we do for new
with DECL_IS_OPERATOR_NEW. Then the middle-end can delete those
calls (the flag would mean there's no side-effect in case you pass NULL).
Richard.
> Cheers,
> Daniel
More information about the Gcc
mailing list