diff --git a/libstdc++-v3/config/cpu/generic/atomicity_mutex/atomicity.h b/libstdc++-v3/config/cpu/generic/atomicity_mutex/atomicity.h index b1328c025bc..7d5772d5484 100644 --- a/libstdc++-v3/config/cpu/generic/atomicity_mutex/atomicity.h +++ b/libstdc++-v3/config/cpu/generic/atomicity_mutex/atomicity.h @@ -44,10 +44,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __exchange_and_add(volatile _Atomic_word* __mem, int __val) throw () { __gnu_cxx::__scoped_lock sentry(get_atomic_mutex()); - _Atomic_word __result; - __result = *__mem; - *__mem += __val; - return __result; + return __gnu_cxx::__exchange_and_add_single(__mem, __val); } void diff --git a/libstdc++-v3/include/ext/atomicity.h b/libstdc++-v3/include/ext/atomicity.h index 650b786cd8e..0b970f33f4b 100644 --- a/libstdc++-v3/include/ext/atomicity.h +++ b/libstdc++-v3/include/ext/atomicity.h @@ -39,6 +39,9 @@ #if __has_include() # include #endif +#if __cplusplus >= 201103L +# include // make_unsigned_t +#endif namespace __gnu_cxx _GLIBCXX_VISIBILITY(default) { @@ -79,19 +82,47 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __atomic_add(volatile _Atomic_word*, int) _GLIBCXX_NOTHROW; #endif +#if __cplusplus < 201103L + // The array bound will be ill-formed in the very unlikely case that + // _Atomic_word is wider than long and we need to use unsigned long long + // below in __exchange_and_add_single and __atomic_add_single. + typedef int + _Atomic_word_fits_in_long[sizeof(_Atomic_word) <= sizeof(long) ? 1 : -1]; +#endif + inline _Atomic_word __attribute__((__always_inline__)) __exchange_and_add_single(_Atomic_word* __mem, int __val) { _Atomic_word __result = *__mem; - *__mem += __val; + // Do the addition with an unsigned type so that overflow is well defined. +#if __cplusplus >= 201103L + std::make_unsigned<_Atomic_word>::type __u; +#else + // For most targets make_unsigned_t<_Atomic_word> is unsigned int, + // but 64-bit sparc uses long for _Atomic_word. + // Sign-extending to unsigned long works for both cases. + unsigned long __u; +#endif + __u = __result; + __u += __val; + *__mem = __u; return __result; } inline void __attribute__((__always_inline__)) __atomic_add_single(_Atomic_word* __mem, int __val) - { *__mem += __val; } + { +#if __cplusplus >= 201103L + std::make_unsigned<_Atomic_word>::type __u; +#else + unsigned long __u; // see above +#endif + __u = *__mem; + __u += __val; + *__mem = __u; + } inline _Atomic_word __attribute__ ((__always_inline__)) diff --git a/libstdc++-v3/libsupc++/Makefile.am b/libstdc++-v3/libsupc++/Makefile.am index 60e7d1594e6..098d93719ce 100644 --- a/libstdc++-v3/libsupc++/Makefile.am +++ b/libstdc++-v3/libsupc++/Makefile.am @@ -132,6 +132,11 @@ atomicity_file = ${glibcxx_srcdir}/$(ATOMICITY_SRCDIR)/atomicity.h atomicity.cc: ${atomicity_file} $(LN_S) ${atomicity_file} ./atomicity.cc || true +atomicity.lo: atomicity.cc + $(LTCOMPILE) -fwrapv -c $< +atomicity.o: atomicity.cc + $(CXXCOMPILE) -fwrapv -c $< + if OS_IS_DARWIN # See PR 112397 new_opvnt.lo: new_opvnt.cc diff --git a/libstdc++-v3/libsupc++/Makefile.in b/libstdc++-v3/libsupc++/Makefile.in index 732ab89c8a2..b691915e396 100644 --- a/libstdc++-v3/libsupc++/Makefile.in +++ b/libstdc++-v3/libsupc++/Makefile.in @@ -973,6 +973,11 @@ cp-demangle.o: cp-demangle.c atomicity.cc: ${atomicity_file} $(LN_S) ${atomicity_file} ./atomicity.cc || true +atomicity.lo: atomicity.cc + $(LTCOMPILE) -fwrapv -c $< +atomicity.o: atomicity.cc + $(CXXCOMPILE) -fwrapv -c $< + # See PR 112397 @OS_IS_DARWIN_TRUE@new_opvnt.lo: new_opvnt.cc @OS_IS_DARWIN_TRUE@ $(LTCXXCOMPILE) -fno-reorder-blocks-and-partition -I. -c $<