This fixes a 5/6 regression that causes atomic<int>::is_lock_free() to require libatomic even on targets where the compiler knows the answer.
The new test only runs on x86_64-linux and powerpc*-linux. It isn't actually OS-dependent but as long as it runs somewhere we should pick up regressions so those commonly-tested targets are sufficient. Tested x86_64-linux and powerpc64le-linux. Richard, this is your middle-end change plus your suggestion for the std::atomic members, which works just as you said it would. OK for trunk?
commit db33491a59064c80104d8482f92cbf80d0d9775c Author: Jonathan Wakely <jwak...@redhat.com> Date: Thu Sep 17 00:21:34 2015 +0100 Handle alignment in __atomic_is_lock_free gcc: 2015-09-17 Richard Henderson <r...@redhat.com> PR libstdc++/65913 * builtins.c (fold_builtin_atomic_always_lock_free): Handle fake pointers that encode the alignment of the object. libstdc++-v3: 2015-09-17 Jonathan Wakely <jwak...@redhat.com> PR libstdc++/65913 * include/bits/atomic_base.h (__atomic_base<_TTp>::is_lock_free(), __atomic_base<_PTp*>::is_lock_free()): Call the built-in with the immediate pointer value, not a variable. * include/std/atomic (atomic<T>::is_lock_free()): Likewise. * testsuite/29_atomics/atomic/65913.cc: New. diff --git a/gcc/builtins.c b/gcc/builtins.c index d79372c..aeec170 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -5635,8 +5635,20 @@ fold_builtin_atomic_always_lock_free (tree arg0, tree arg1) mode = mode_for_size (size, MODE_INT, 0); mode_align = GET_MODE_ALIGNMENT (mode); - if (TREE_CODE (arg1) == INTEGER_CST && INTVAL (expand_normal (arg1)) == 0) - type_align = mode_align; + if (TREE_CODE (arg1) == INTEGER_CST) + { + unsigned HOST_WIDE_INT val = UINTVAL (expand_normal (arg1)); + + /* Either this argument is null, or it's a fake pointer encoding + the alignment of the object. */ + val = val & -val; + val *= BITS_PER_UNIT; + + if (val == 0 || mode_align < val) + type_align = mode_align; + else + type_align = val; + } else { tree ttype = TREE_TYPE (arg1); diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h index 79769cf..75a7ca7 100644 --- a/libstdc++-v3/include/bits/atomic_base.h +++ b/libstdc++-v3/include/bits/atomic_base.h @@ -350,17 +350,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION bool is_lock_free() const noexcept { - // Produce a fake, minimally aligned pointer. - void *__a = reinterpret_cast<void *>(-__alignof(_M_i)); - return __atomic_is_lock_free(sizeof(_M_i), __a); + // Use a fake, minimally aligned pointer. + return __atomic_is_lock_free(sizeof(_M_i), + reinterpret_cast<void *>(-__alignof(_M_i))); } bool is_lock_free() const volatile noexcept { - // Produce a fake, minimally aligned pointer. - void *__a = reinterpret_cast<void *>(-__alignof(_M_i)); - return __atomic_is_lock_free(sizeof(_M_i), __a); + // Use a fake, minimally aligned pointer. + return __atomic_is_lock_free(sizeof(_M_i), + reinterpret_cast<void *>(-__alignof(_M_i))); } _GLIBCXX_ALWAYS_INLINE void @@ -666,16 +666,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION is_lock_free() const noexcept { // Produce a fake, minimally aligned pointer. - void *__a = reinterpret_cast<void *>(-__alignof(_M_p)); - return __atomic_is_lock_free(sizeof(_M_p), __a); + return __atomic_is_lock_free(sizeof(_M_p), + reinterpret_cast<void *>(-__alignof(_M_p))); } bool is_lock_free() const volatile noexcept { // Produce a fake, minimally aligned pointer. - void *__a = reinterpret_cast<void *>(-__alignof(_M_p)); - return __atomic_is_lock_free(sizeof(_M_p), __a); + return __atomic_is_lock_free(sizeof(_M_p), + reinterpret_cast<void *>(-__alignof(_M_p))); } _GLIBCXX_ALWAYS_INLINE void diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic index 125e37a..cdd1f0b 100644 --- a/libstdc++-v3/include/std/atomic +++ b/libstdc++-v3/include/std/atomic @@ -208,16 +208,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION is_lock_free() const noexcept { // Produce a fake, minimally aligned pointer. - void *__a = reinterpret_cast<void *>(-__alignof(_M_i)); - return __atomic_is_lock_free(sizeof(_M_i), __a); + return __atomic_is_lock_free(sizeof(_M_i), + reinterpret_cast<void *>(-__alignof(_M_i))); } bool is_lock_free() const volatile noexcept { // Produce a fake, minimally aligned pointer. - void *__a = reinterpret_cast<void *>(-__alignof(_M_i)); - return __atomic_is_lock_free(sizeof(_M_i), __a); + return __atomic_is_lock_free(sizeof(_M_i), + reinterpret_cast<void *>(-__alignof(_M_i))); } void diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/65913.cc b/libstdc++-v3/testsuite/29_atomics/atomic/65913.cc new file mode 100644 index 0000000..dbdd9cf --- /dev/null +++ b/libstdc++-v3/testsuite/29_atomics/atomic/65913.cc @@ -0,0 +1,39 @@ +// Copyright (C) 2015 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// { dg-do run { target x86_64-*-linux* powerpc*-*-linux* } } +// { dg-options "-std=gnu++11 -O0" } + +#include <atomic> +#include <testsuite_hooks.h> + +// PR libstdc++/65913 + +void +test01() +{ + struct Int { int i; }; + VERIFY( std::atomic<Int>{}.is_lock_free() ); + VERIFY( std::atomic<int>{}.is_lock_free() ); + VERIFY( std::atomic<int*>{}.is_lock_free() ); +} + +int +main() +{ + test01(); +}