https://github.com/ldionne updated https://github.com/llvm/llvm-project/pull/68753
>From 5e53337f16aa446d6a2dc764d347ea37b22c3a56 Mon Sep 17 00:00:00 2001 From: Louis Dionne <ldionn...@gmail.com> Date: Tue, 10 Oct 2023 16:35:11 -0700 Subject: [PATCH 1/4] [libc++] Allow running the test suite with optimizations This patch adds a configuration of the libc++ test suite that enables optimizations when building the tests. It also adds a new CI configuration to exercise this on a regular basis. This is added in the context of [1], which requires building with optimizations in order to hit the bug. [1]: https://github.com/llvm/llvm-project/issues/68552 --- .github/workflows/libcxx-build-and-test.yaml | 2 +- .../caches/Generic-optimized-speed.cmake | 4 +++ .../support.dynamic/libcpp_deallocate.sh.cpp | 17 +++++------ .../path.member/path.assign/move.pass.cpp | 2 +- .../path.member/path.construct/move.pass.cpp | 2 +- .../new.size.replace.indirect.pass.cpp | 3 +- .../new.size.replace.pass.cpp | 3 +- .../new.size_align.replace.indirect.pass.cpp | 7 +++-- ...ze_align_nothrow.replace.indirect.pass.cpp | 7 +++-- .../new.size_align_nothrow.replace.pass.cpp | 7 +++-- ...new.size_nothrow.replace.indirect.pass.cpp | 3 +- .../new.size_nothrow.replace.pass.cpp | 3 +- .../new.size.replace.pass.cpp | 3 +- ...ze_align_nothrow.replace.indirect.pass.cpp | 7 +++-- ...new.size_nothrow.replace.indirect.pass.cpp | 3 +- .../func.wrap.func.alg/swap.pass.cpp | 16 +++++------ .../func.wrap.func.con/F.pass.cpp | 2 +- .../func.wrap.func.con/copy_assign.pass.cpp | 8 +++--- .../func.wrap.func.con/copy_move.pass.cpp | 8 +++--- .../nullptr_t_assign.pass.cpp | 2 +- .../func.wrap.func.mod/swap.pass.cpp | 12 ++++---- .../make_shared.pass.cpp | 4 +-- libcxx/test/support/count_new.h | 5 ++++ libcxx/test/support/do_not_optimize.h | 28 +++++++++++++++++++ libcxx/utils/ci/run-buildbot | 5 ++++ libcxx/utils/libcxx/test/params.py | 28 ++++++++++++++++++- libunwind/test/libunwind_02.pass.cpp | 26 +++++++++++++---- libunwind/test/unw_resume.pass.cpp | 2 +- libunwind/test/unwind_leaffunction.pass.cpp | 20 +++++++------ 29 files changed, 169 insertions(+), 70 deletions(-) create mode 100644 libcxx/cmake/caches/Generic-optimized-speed.cmake create mode 100644 libcxx/test/support/do_not_optimize.h diff --git a/.github/workflows/libcxx-build-and-test.yaml b/.github/workflows/libcxx-build-and-test.yaml index 018f0e45a2441ef..9c7adb808bcb34f 100644 --- a/.github/workflows/libcxx-build-and-test.yaml +++ b/.github/workflows/libcxx-build-and-test.yaml @@ -162,6 +162,7 @@ jobs: 'generic-no-tzdb', 'generic-no-unicode', 'generic-no-wide-characters', + 'generic-optimized-speed', 'generic-static', 'generic-with_llvm_unwinder', # TODO Find a better place for the benchmark and bootstrapping builds to live. They're either very expensive @@ -209,4 +210,3 @@ jobs: **/CMakeError.log **/CMakeOutput.log **/crash_diagnostics/* - diff --git a/libcxx/cmake/caches/Generic-optimized-speed.cmake b/libcxx/cmake/caches/Generic-optimized-speed.cmake new file mode 100644 index 000000000000000..577a5de9f34c539 --- /dev/null +++ b/libcxx/cmake/caches/Generic-optimized-speed.cmake @@ -0,0 +1,4 @@ +set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "") +set(LIBCXX_TEST_PARAMS "optimization=speed" CACHE STRING "") +set(LIBCXXABI_TEST_PARAMS "${LIBCXX_TEST_PARAMS}" CACHE STRING "") +set(LIBUNWIND_TEST_PARAMS "${LIBCXX_TEST_PARAMS}" CACHE STRING "") diff --git a/libcxx/test/libcxx/language.support/support.dynamic/libcpp_deallocate.sh.cpp b/libcxx/test/libcxx/language.support/support.dynamic/libcpp_deallocate.sh.cpp index fb56ce4518a7182..6e6229b752a7a6e 100644 --- a/libcxx/test/libcxx/language.support/support.dynamic/libcpp_deallocate.sh.cpp +++ b/libcxx/test/libcxx/language.support/support.dynamic/libcpp_deallocate.sh.cpp @@ -34,6 +34,7 @@ #include <cstdlib> #include <new> +#include "do_not_optimize.h" #include "test_macros.h" TEST_DIAGNOSTIC_PUSH @@ -187,13 +188,13 @@ void test_allocator_and_new_match() { stats.reset(); #if defined(NO_SIZE) && defined(NO_ALIGN) { - int* x = new int(42); + int* x = support::do_not_optimize(new int(42)); delete x; assert(stats.expect_plain()); } stats.reset(); { - AlignedType* a = new AlignedType(); + AlignedType* a = support::do_not_optimize(new AlignedType()); delete a; assert(stats.expect_plain()); } @@ -202,14 +203,14 @@ void test_allocator_and_new_match() { stats.reset(); #if TEST_STD_VER >= 11 { - int* x = new int(42); + int* x = support::do_not_optimize(new int(42)); delete x; assert(stats.expect_plain()); } #endif stats.reset(); { - AlignedType* a = new AlignedType(); + AlignedType* a = support::do_not_optimize(new AlignedType()); delete a; assert(stats.expect_align(TEST_ALIGNOF(AlignedType))); } @@ -217,13 +218,13 @@ void test_allocator_and_new_match() { #elif defined(NO_ALIGN) stats.reset(); { - int* x = new int(42); + int* x = support::do_not_optimize(new int(42)); delete x; assert(stats.expect_size(sizeof(int))); } stats.reset(); { - AlignedType* a = new AlignedType(); + AlignedType* a = support::do_not_optimize(new AlignedType()); delete a; assert(stats.expect_size(sizeof(AlignedType))); } @@ -231,13 +232,13 @@ void test_allocator_and_new_match() { #else stats.reset(); { - int* x = new int(42); + int* x = support::do_not_optimize(new int(42)); delete x; assert(stats.expect_size(sizeof(int))); } stats.reset(); { - AlignedType* a = new AlignedType(); + AlignedType* a = support::do_not_optimize(new AlignedType()); delete a; assert(stats.expect_size_align(sizeof(AlignedType), TEST_ALIGNOF(AlignedType))); diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.assign/move.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.assign/move.pass.cpp index 0efd9596f1c2bda..93295d9f6d5f382 100644 --- a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.assign/move.pass.cpp +++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.assign/move.pass.cpp @@ -31,7 +31,7 @@ int main(int, char**) { const std::string s("we really really really really really really really " "really really long string so that we allocate"); ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS( - globalMemCounter.checkOutstandingNewEq(1)); + globalMemCounter.checkOutstandingNewLessThanOrEqual(1)); const fs::path::string_type ps(s.begin(), s.end()); path p(s); { diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/move.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/move.pass.cpp index 15782dffa7df891..3c762ee676be4e9 100644 --- a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/move.pass.cpp +++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/move.pass.cpp @@ -31,7 +31,7 @@ int main(int, char**) { const std::string s("we really really really really really really really " "really really long string so that we allocate"); ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS( - globalMemCounter.checkOutstandingNewEq(1)); + globalMemCounter.checkOutstandingNewLessThanOrEqual(1)); const fs::path::string_type ps(s.begin(), s.end()); path p(s); { diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.replace.indirect.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.replace.indirect.pass.cpp index 172b6cc2f2944ad..13f6217c521fa8f 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.replace.indirect.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.replace.indirect.pass.cpp @@ -20,6 +20,7 @@ #include <cassert> #include <limits> +#include "do_not_optimize.h" #include "test_macros.h" int new_called = 0; @@ -40,7 +41,7 @@ void operator delete(void* p) TEST_NOEXCEPT { int main(int, char**) { new_called = delete_called = 0; - int* x = new int[3]; + int* x = support::do_not_optimize(new int[3]); assert(x != nullptr); ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_called == 1); diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.replace.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.replace.pass.cpp index e352c00b4d0af94..9b3d39986484ddd 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.replace.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.replace.pass.cpp @@ -19,6 +19,7 @@ #include <cassert> #include <limits> +#include "do_not_optimize.h" #include "test_macros.h" int new_called = 0; @@ -38,7 +39,7 @@ void operator delete[](void* p) TEST_NOEXCEPT { int main(int, char**) { new_called = delete_called = 0; - int* x = new int[3]; + int* x = support::do_not_optimize(new int[3]); assert(x != nullptr); ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_called == 1); diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align.replace.indirect.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align.replace.indirect.pass.cpp index dcaa76a650d37c4..014951f50b7eb7e 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align.replace.indirect.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align.replace.indirect.pass.cpp @@ -26,6 +26,7 @@ #include <cassert> #include <limits> +#include "do_not_optimize.h" #include "test_macros.h" #include "../types.h" @@ -51,7 +52,7 @@ int main(int, char**) { // Test with an overaligned type { new_called = delete_called = 0; - OverAligned* x = new OverAligned[3]; + OverAligned* x = support::do_not_optimize(new OverAligned[3]); ASSERT_WITH_OPERATOR_NEW_FALLBACKS(static_cast<void*>(x) == DummyData); ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_called == 1); @@ -62,7 +63,7 @@ int main(int, char**) { // Test with a type that is right on the verge of being overaligned { new_called = delete_called = 0; - MaxAligned* x = new MaxAligned[3]; + MaxAligned* x = support::do_not_optimize(new MaxAligned[3]); assert(x != nullptr); assert(new_called == 0); @@ -73,7 +74,7 @@ int main(int, char**) { // Test with a type that is clearly not overaligned { new_called = delete_called = 0; - int* x = new int[3]; + int* x = support::do_not_optimize(new int[3]); assert(x != nullptr); assert(new_called == 0); diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align_nothrow.replace.indirect.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align_nothrow.replace.indirect.pass.cpp index eba8a9026fa459c..99926b876a03825 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align_nothrow.replace.indirect.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align_nothrow.replace.indirect.pass.cpp @@ -26,6 +26,7 @@ #include <cassert> #include <limits> +#include "do_not_optimize.h" #include "test_macros.h" #include "../types.h" @@ -51,7 +52,7 @@ int main(int, char**) { // Test with an overaligned type { new_called = delete_called = 0; - OverAligned* x = new (std::nothrow) OverAligned[3]; + OverAligned* x = support::do_not_optimize(new (std::nothrow) OverAligned[3]); ASSERT_WITH_OPERATOR_NEW_FALLBACKS(static_cast<void*>(x) == DummyData); ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_called == 1); @@ -62,7 +63,7 @@ int main(int, char**) { // Test with a type that is right on the verge of being overaligned { new_called = delete_called = 0; - MaxAligned* x = new (std::nothrow) MaxAligned[3]; + MaxAligned* x = support::do_not_optimize(new (std::nothrow) MaxAligned[3]); assert(x != nullptr); assert(new_called == 0); @@ -73,7 +74,7 @@ int main(int, char**) { // Test with a type that is clearly not overaligned { new_called = delete_called = 0; - int* x = new (std::nothrow) int[3]; + int* x = support::do_not_optimize(new (std::nothrow) int[3]); assert(x != nullptr); assert(new_called == 0); diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align_nothrow.replace.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align_nothrow.replace.pass.cpp index 62a040e297ae56b..cd8af782f9726d0 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align_nothrow.replace.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align_nothrow.replace.pass.cpp @@ -23,6 +23,7 @@ #include <cassert> #include <limits> +#include "do_not_optimize.h" #include "test_macros.h" #include "../types.h" @@ -48,7 +49,7 @@ int main(int, char**) { // Test with an overaligned type { new_nothrow_called = delete_called = 0; - OverAligned* x = new (std::nothrow) OverAligned[3]; + OverAligned* x = support::do_not_optimize(new (std::nothrow) OverAligned[3]); assert(static_cast<void*>(x) == DummyData); ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_nothrow_called == 1); @@ -59,7 +60,7 @@ int main(int, char**) { // Test with a type that is right on the verge of being overaligned { new_nothrow_called = delete_called = 0; - MaxAligned* x = new (std::nothrow) MaxAligned[3]; + MaxAligned* x = support::do_not_optimize(new (std::nothrow) MaxAligned[3]); assert(x != nullptr); assert(new_nothrow_called == 0); @@ -70,7 +71,7 @@ int main(int, char**) { // Test with a type that is clearly not overaligned { new_nothrow_called = delete_called = 0; - int* x = new (std::nothrow) int[3]; + int* x = support::do_not_optimize(new (std::nothrow) int[3]); assert(x != nullptr); assert(new_nothrow_called == 0); diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_nothrow.replace.indirect.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_nothrow.replace.indirect.pass.cpp index 8ad0292dcb5ca4b..8b0d801acd1fcc6 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_nothrow.replace.indirect.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_nothrow.replace.indirect.pass.cpp @@ -24,6 +24,7 @@ #include <cstdlib> #include <cassert> +#include "do_not_optimize.h" #include "test_macros.h" int new_called = 0; @@ -44,7 +45,7 @@ void operator delete(void* p) TEST_NOEXCEPT { int main(int, char**) { new_called = delete_called = 0; - int* x = new (std::nothrow) int[3]; + int* x = support::do_not_optimize(new (std::nothrow) int[3]); assert(x != nullptr); ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_called == 1); diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_nothrow.replace.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_nothrow.replace.pass.cpp index b85e15ce64b48ac..c9e4942d8153166 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_nothrow.replace.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_nothrow.replace.pass.cpp @@ -18,6 +18,7 @@ #include <cstdlib> #include <cassert> +#include "do_not_optimize.h" #include "test_macros.h" int new_nothrow_called = 0; @@ -35,7 +36,7 @@ void operator delete[](void* p) TEST_NOEXCEPT { int main(int, char**) { new_nothrow_called = delete_called = 0; - int* x = new (std::nothrow) int[3]; + int* x = support::do_not_optimize(new (std::nothrow) int[3]); assert(x != nullptr); ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_nothrow_called == 1); diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size.replace.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size.replace.pass.cpp index a03313e5872ef3b..c62268c39027c8d 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size.replace.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size.replace.pass.cpp @@ -17,6 +17,7 @@ #include <cstdlib> #include <cassert> +#include "do_not_optimize.h" #include "test_macros.h" int new_called = 0; @@ -36,7 +37,7 @@ void operator delete(void* p) TEST_NOEXCEPT { int main(int, char**) { new_called = delete_called = 0; - int* x = new int(3); + int* x = support::do_not_optimize(new int(3)); assert(x != nullptr); ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_called == 1); diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_align_nothrow.replace.indirect.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_align_nothrow.replace.indirect.pass.cpp index 4a18ad2df8f2aa5..1c42cdbb50db6b2 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_align_nothrow.replace.indirect.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_align_nothrow.replace.indirect.pass.cpp @@ -25,6 +25,7 @@ #include <cassert> #include <limits> +#include "do_not_optimize.h" #include "test_macros.h" #include "../types.h" @@ -50,7 +51,7 @@ int main(int, char**) { // Test with an overaligned type { new_called = delete_called = 0; - OverAligned* x = new (std::nothrow) OverAligned; + OverAligned* x = support::do_not_optimize(new (std::nothrow) OverAligned); ASSERT_WITH_OPERATOR_NEW_FALLBACKS(static_cast<void*>(x) == DummyData); ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_called == 1); @@ -61,7 +62,7 @@ int main(int, char**) { // Test with a type that is right on the verge of being overaligned { new_called = delete_called = 0; - MaxAligned* x = new (std::nothrow) MaxAligned; + MaxAligned* x = support::do_not_optimize(new (std::nothrow) MaxAligned); assert(x != nullptr); assert(new_called == 0); @@ -72,7 +73,7 @@ int main(int, char**) { // Test with a type that is clearly not overaligned { new_called = delete_called = 0; - int* x = new (std::nothrow) int; + int* x = support::do_not_optimize(new (std::nothrow) int); assert(x != nullptr); assert(new_called == 0); diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_nothrow.replace.indirect.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_nothrow.replace.indirect.pass.cpp index 2ae0dfa4f1abc41..e5f91ad44fc0cf3 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_nothrow.replace.indirect.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_nothrow.replace.indirect.pass.cpp @@ -19,6 +19,7 @@ #include <cstdlib> #include <cassert> +#include "do_not_optimize.h" #include "test_macros.h" int new_called = 0; @@ -39,7 +40,7 @@ void operator delete(void* p) TEST_NOEXCEPT { int main(int, char**) { new_called = delete_called = 0; - int* x = new (std::nothrow) int(3); + int* x = support::do_not_optimize(new (std::nothrow) int(3)); assert(x != nullptr); ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_called == 1); diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.alg/swap.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.alg/swap.pass.cpp index 3924274190c41b1..97f78ac62dab03f 100644 --- a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.alg/swap.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.alg/swap.pass.cpp @@ -69,12 +69,12 @@ int main(int, char**) static_assert(noexcept(swap(f1, f2)), "" ); #endif assert(A::count == 2); - assert(globalMemCounter.checkOutstandingNewEq(2)); + assert(globalMemCounter.checkOutstandingNewLessThanOrEqual(2)); RTTI_ASSERT(f1.target<A>()->id() == 1); RTTI_ASSERT(f2.target<A>()->id() == 2); swap(f1, f2); assert(A::count == 2); - assert(globalMemCounter.checkOutstandingNewEq(2)); + assert(globalMemCounter.checkOutstandingNewLessThanOrEqual(2)); RTTI_ASSERT(f1.target<A>()->id() == 2); RTTI_ASSERT(f2.target<A>()->id() == 1); } @@ -87,12 +87,12 @@ int main(int, char**) static_assert(noexcept(swap(f1, f2)), "" ); #endif assert(A::count == 1); - assert(globalMemCounter.checkOutstandingNewEq(1)); + assert(globalMemCounter.checkOutstandingNewLessThanOrEqual(1)); RTTI_ASSERT(f1.target<A>()->id() == 1); RTTI_ASSERT(*f2.target<int(*)(int)>() == g); swap(f1, f2); assert(A::count == 1); - assert(globalMemCounter.checkOutstandingNewEq(1)); + assert(globalMemCounter.checkOutstandingNewLessThanOrEqual(1)); RTTI_ASSERT(*f1.target<int(*)(int)>() == g); RTTI_ASSERT(f2.target<A>()->id() == 1); } @@ -105,12 +105,12 @@ int main(int, char**) static_assert(noexcept(swap(f1, f2)), "" ); #endif assert(A::count == 1); - assert(globalMemCounter.checkOutstandingNewEq(1)); + assert(globalMemCounter.checkOutstandingNewLessThanOrEqual(1)); RTTI_ASSERT(*f1.target<int(*)(int)>() == g); RTTI_ASSERT(f2.target<A>()->id() == 1); swap(f1, f2); assert(A::count == 1); - assert(globalMemCounter.checkOutstandingNewEq(1)); + assert(globalMemCounter.checkOutstandingNewLessThanOrEqual(1)); RTTI_ASSERT(f1.target<A>()->id() == 1); RTTI_ASSERT(*f2.target<int(*)(int)>() == g); } @@ -123,12 +123,12 @@ int main(int, char**) static_assert(noexcept(swap(f1, f2)), "" ); #endif assert(A::count == 0); - assert(globalMemCounter.checkOutstandingNewEq(0)); + assert(globalMemCounter.checkOutstandingNewLessThanOrEqual(0)); RTTI_ASSERT(*f1.target<int(*)(int)>() == g); RTTI_ASSERT(*f2.target<int(*)(int)>() == h); swap(f1, f2); assert(A::count == 0); - assert(globalMemCounter.checkOutstandingNewEq(0)); + assert(globalMemCounter.checkOutstandingNewLessThanOrEqual(0)); RTTI_ASSERT(*f1.target<int(*)(int)>() == h); RTTI_ASSERT(*f2.target<int(*)(int)>() == g); } diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/F.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/F.pass.cpp index c1ad528254af1a4..92409577d60de51 100644 --- a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/F.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/F.pass.cpp @@ -69,7 +69,7 @@ int main(int, char**) { std::function<int(int)> f = A(); assert(A::count == 1); - assert(globalMemCounter.checkOutstandingNewEq(1)); + assert(globalMemCounter.checkOutstandingNewLessThanOrEqual(1)); RTTI_ASSERT(f.target<A>()); RTTI_ASSERT(f.target<int(*)(int)>() == 0); } diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/copy_assign.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/copy_assign.pass.cpp index 75eaa55dc71edd3..e3bd6ef78d61029 100644 --- a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/copy_assign.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/copy_assign.pass.cpp @@ -57,13 +57,13 @@ int main(int, char**) { { std::function<int(int)> f = A(); assert(A::count == 1); - assert(globalMemCounter.checkOutstandingNewEq(1)); + assert(globalMemCounter.checkOutstandingNewLessThanOrEqual(1)); RTTI_ASSERT(f.target<A>()); RTTI_ASSERT(f.target<int (*)(int)>() == 0); std::function<int(int)> f2; f2 = f; assert(A::count == 2); - assert(globalMemCounter.checkOutstandingNewEq(2)); + assert(globalMemCounter.checkOutstandingNewLessThanOrEqual(2)); RTTI_ASSERT(f2.target<A>()); RTTI_ASSERT(f2.target<int (*)(int)>() == 0); } @@ -125,13 +125,13 @@ int main(int, char**) { { std::function<int(int)> f = A(); assert(A::count == 1); - assert(globalMemCounter.checkOutstandingNewEq(1)); + assert(globalMemCounter.checkOutstandingNewLessThanOrEqual(1)); RTTI_ASSERT(f.target<A>()); RTTI_ASSERT(f.target<int (*)(int)>() == 0); std::function<int(int)> f2; f2 = std::move(f); assert(A::count == 1); - assert(globalMemCounter.checkOutstandingNewEq(1)); + assert(globalMemCounter.checkOutstandingNewLessThanOrEqual(1)); RTTI_ASSERT(f2.target<A>()); RTTI_ASSERT(f2.target<int (*)(int)>() == 0); RTTI_ASSERT(f.target<A>() == 0); diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/copy_move.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/copy_move.pass.cpp index 4a2a272ae0a3b9d..5b3f4f10cadbb5e 100644 --- a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/copy_move.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/copy_move.pass.cpp @@ -64,12 +64,12 @@ int main(int, char**) { std::function<int(int)> f = A(); assert(A::count == 1); - assert(globalMemCounter.checkOutstandingNewEq(1)); + assert(globalMemCounter.checkOutstandingNewLessThanOrEqual(1)); RTTI_ASSERT(f.target<A>()); RTTI_ASSERT(f.target<int(*)(int)>() == 0); std::function<int(int)> f2 = f; assert(A::count == 2); - assert(globalMemCounter.checkOutstandingNewEq(2)); + assert(globalMemCounter.checkOutstandingNewLessThanOrEqual(2)); RTTI_ASSERT(f2.target<A>()); RTTI_ASSERT(f2.target<int(*)(int)>() == 0); } @@ -113,7 +113,7 @@ int main(int, char**) { // Test rvalue references std::function<int(int)> f = A(); assert(A::count == 1); - assert(globalMemCounter.checkOutstandingNewEq(1)); + assert(globalMemCounter.checkOutstandingNewLessThanOrEqual(1)); RTTI_ASSERT(f.target<A>()); RTTI_ASSERT(f.target<int(*)(int)>() == 0); LIBCPP_ASSERT_NOEXCEPT(std::function<int(int)>(std::move(f))); @@ -122,7 +122,7 @@ int main(int, char**) #endif std::function<int(int)> f2 = std::move(f); assert(A::count == 1); - assert(globalMemCounter.checkOutstandingNewEq(1)); + assert(globalMemCounter.checkOutstandingNewLessThanOrEqual(1)); RTTI_ASSERT(f2.target<A>()); RTTI_ASSERT(f2.target<int(*)(int)>() == 0); RTTI_ASSERT(f.target<A>() == 0); diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/nullptr_t_assign.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/nullptr_t_assign.pass.cpp index 391e2a7434bf715..b2f61fa9b68a27c 100644 --- a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/nullptr_t_assign.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/nullptr_t_assign.pass.cpp @@ -57,7 +57,7 @@ int main(int, char**) { std::function<int(int)> f = A(); assert(A::count == 1); - assert(globalMemCounter.checkOutstandingNewEq(1)); + assert(globalMemCounter.checkOutstandingNewLessThanOrEqual(1)); RTTI_ASSERT(f.target<A>()); f = nullptr; assert(A::count == 0); diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.mod/swap.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.mod/swap.pass.cpp index d51c35ea44fa058..1723ddfd33bedc7 100644 --- a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.mod/swap.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.mod/swap.pass.cpp @@ -68,12 +68,12 @@ int main(int, char**) { std::function<int(int)> f1 = A(1); std::function<int(int)> f2 = A(2); assert(A::count == 2); - assert(globalMemCounter.checkOutstandingNewEq(2)); + assert(globalMemCounter.checkOutstandingNewLessThanOrEqual(2)); RTTI_ASSERT(f1.target<A>()->id() == 1); RTTI_ASSERT(f2.target<A>()->id() == 2); f1.swap(f2); assert(A::count == 2); - assert(globalMemCounter.checkOutstandingNewEq(2)); + assert(globalMemCounter.checkOutstandingNewLessThanOrEqual(2)); RTTI_ASSERT(f1.target<A>()->id() == 2); RTTI_ASSERT(f2.target<A>()->id() == 1); } @@ -83,12 +83,12 @@ int main(int, char**) { std::function<int(int)> f1 = A(1); std::function<int(int)> f2 = g; assert(A::count == 1); - assert(globalMemCounter.checkOutstandingNewEq(1)); + assert(globalMemCounter.checkOutstandingNewLessThanOrEqual(1)); RTTI_ASSERT(f1.target<A>()->id() == 1); RTTI_ASSERT(*f2.target<int (*)(int)>() == g); f1.swap(f2); assert(A::count == 1); - assert(globalMemCounter.checkOutstandingNewEq(1)); + assert(globalMemCounter.checkOutstandingNewLessThanOrEqual(1)); RTTI_ASSERT(*f1.target<int (*)(int)>() == g); RTTI_ASSERT(f2.target<A>()->id() == 1); } @@ -98,12 +98,12 @@ int main(int, char**) { std::function<int(int)> f1 = g; std::function<int(int)> f2 = A(1); assert(A::count == 1); - assert(globalMemCounter.checkOutstandingNewEq(1)); + assert(globalMemCounter.checkOutstandingNewLessThanOrEqual(1)); RTTI_ASSERT(*f1.target<int (*)(int)>() == g); RTTI_ASSERT(f2.target<A>()->id() == 1); f1.swap(f2); assert(A::count == 1); - assert(globalMemCounter.checkOutstandingNewEq(1)); + assert(globalMemCounter.checkOutstandingNewLessThanOrEqual(1)); RTTI_ASSERT(f1.target<A>()->id() == 1); RTTI_ASSERT(*f2.target<int (*)(int)>() == g); } diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/make_shared.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/make_shared.pass.cpp index 23a904f8ae11f7f..be7505f218cdd0c 100644 --- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/make_shared.pass.cpp +++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/make_shared.pass.cpp @@ -96,7 +96,7 @@ int main(int, char**) int i = 67; char c = 'e'; std::shared_ptr<A> p = std::make_shared<A>(i, c); - assert(globalMemCounter.checkOutstandingNewEq(nc+1)); + assert(globalMemCounter.checkOutstandingNewLessThanOrEqual(nc+1)); assert(A::count == 1); assert(p->get_int() == 67); assert(p->get_char() == 'e'); @@ -116,7 +116,7 @@ int main(int, char**) { char c = 'e'; std::shared_ptr<A> p = std::make_shared<A>(67, c); - assert(globalMemCounter.checkOutstandingNewEq(nc+1)); + assert(globalMemCounter.checkOutstandingNewLessThanOrEqual(nc+1)); assert(A::count == 1); assert(p->get_int() == 67); assert(p->get_char() == 'e'); diff --git a/libcxx/test/support/count_new.h b/libcxx/test/support/count_new.h index b6424850101625b..ef4306e520b195b 100644 --- a/libcxx/test/support/count_new.h +++ b/libcxx/test/support/count_new.h @@ -181,6 +181,11 @@ class MemCounter return disable_checking || n == outstanding_new; } + bool checkOutstandingNewLessThanOrEqual(int n) const + { + return disable_checking || outstanding_new <= n; + } + bool checkOutstandingNewNotEq(int n) const { return disable_checking || n != outstanding_new; diff --git a/libcxx/test/support/do_not_optimize.h b/libcxx/test/support/do_not_optimize.h new file mode 100644 index 000000000000000..542851a8ea6ae2d --- /dev/null +++ b/libcxx/test/support/do_not_optimize.h @@ -0,0 +1,28 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef SUPPORT_DO_NOT_OPTIMIZE_H +#define SUPPORT_DO_NOT_OPTIMIZE_H + +#include "test_macros.h" + +namespace support { +// This function can be used to hide some objects from compiler optimizations. +// +// For example, this is useful to hide the result of a call to `new` and ensure +// that the compiler doesn't elide the call to new/delete. Otherwise, elliding +// calls to new/delete is allowed by the Standard and compilers actually do it +// when optimizations are enabled. +template <class T> +TEST_CONSTEXPR __attribute__((noinline)) T* do_not_optimize(T* ptr) TEST_NOEXCEPT { + return ptr; +} +} // namespace support + +#endif // SUPPORT_DO_NOT_OPTIMIZE_H diff --git a/libcxx/utils/ci/run-buildbot b/libcxx/utils/ci/run-buildbot index 445b1becee0c2a8..5809d3ee956c71a 100755 --- a/libcxx/utils/ci/run-buildbot +++ b/libcxx/utils/ci/run-buildbot @@ -480,6 +480,11 @@ generic-abi-unstable) generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Generic-abi-unstable.cmake" check-runtimes ;; +generic-optimized-speed) + clean + generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Generic-optimized-speed.cmake" + check-runtimes +;; apple-system) clean diff --git a/libcxx/utils/libcxx/test/params.py b/libcxx/utils/libcxx/test/params.py index 3fedbf972c0c822..cb2bbf8b6b81817 100644 --- a/libcxx/utils/libcxx/test/params.py +++ b/libcxx/utils/libcxx/test/params.py @@ -11,7 +11,7 @@ from pathlib import Path from libcxx.test.dsl import * -from libcxx.test.features import _isMSVC +from libcxx.test.features import _isClang, _isAppleClang, _isGCC, _isMSVC _warningFlags = [ @@ -87,6 +87,21 @@ def getStdFlag(cfg, std): return "-std=" + fallbacks[std] return None +def getSpeedOptimizationFlag(cfg): + if _isClang(cfg) or _isAppleClang(cfg) or _isGCC(cfg): + return "-O3" + elif _isMSVC(cfg): + return "/O2" + else: + raise RuntimeError("Can't figure out what compiler is used in the configuration") + +def getSizeOptimizationFlag(cfg): + if _isClang(cfg) or _isAppleClang(cfg) or _isGCC(cfg): + return "-Os" + elif _isMSVC(cfg): + return "/O1" + else: + raise RuntimeError("Can't figure out what compiler is used in the configuration") # fmt: off DEFAULT_PARAMETERS = [ @@ -118,6 +133,17 @@ def getStdFlag(cfg, std): AddCompileFlag(lambda cfg: getStdFlag(cfg, std)), ], ), + Parameter( + name="optimization", + choices=["none", "speed", "size"], + type=str, + help="The optimization level to use when compiling the test suite.", + default="none", + actions=lambda opt: filter(None, [ + AddCompileFlag(lambda cfg: getSpeedOptimizationFlag(cfg)) if opt == "speed" else None, + AddCompileFlag(lambda cfg: getSizeOptimizationFlag(cfg)) if opt == "size" else None, + ]), + ), Parameter( name="enable_modules", choices=["none", "clang", "clang-lsv"], diff --git a/libunwind/test/libunwind_02.pass.cpp b/libunwind/test/libunwind_02.pass.cpp index ea34cd54222c825..710325e42dc0b2e 100644 --- a/libunwind/test/libunwind_02.pass.cpp +++ b/libunwind/test/libunwind_02.pass.cpp @@ -21,7 +21,7 @@ #define EXPECTED_NUM_FRAMES 50 #define NUM_FRAMES_UPPER_BOUND 100 -_Unwind_Reason_Code callback(_Unwind_Context *context, void *cnt) { +__attribute__((noinline)) _Unwind_Reason_Code callback(_Unwind_Context *context, void *cnt) { (void)context; int *i = (int *)cnt; ++*i; @@ -31,7 +31,7 @@ _Unwind_Reason_Code callback(_Unwind_Context *context, void *cnt) { return _URC_NO_REASON; } -void test_backtrace() { +__attribute__((noinline)) void test_backtrace() { int n = 0; _Unwind_Backtrace(&callback, &n); if (n < EXPECTED_NUM_FRAMES) { @@ -39,17 +39,33 @@ void test_backtrace() { } } -int test(int i) { +// These functions are effectively the same, but we have to be careful to avoid unwanted +// optimizations that would mess with the number of frames we expect. Surprisingly, +// slapping `noinline` is not sufficient -- we also have to avoid writing the function +// in a way that the compiler can easily spot tail recursion. +__attribute__((noinline)) int test1(int i); +__attribute__((noinline)) int test2(int i); + +__attribute__((noinline)) int test1(int i) { + if (i == 0) { + test_backtrace(); + return 0; + } else { + return i + test2(i - 1); + } +} + +__attribute__((noinline)) int test2(int i) { if (i == 0) { test_backtrace(); return 0; } else { - return i + test(i - 1); + return i + test1(i - 1); } } int main(int, char**) { - int total = test(50); + int total = test1(50); assert(total == 1275); return 0; } diff --git a/libunwind/test/unw_resume.pass.cpp b/libunwind/test/unw_resume.pass.cpp index 08e8d4edeaf2927..2b7470b5cad0eb7 100644 --- a/libunwind/test/unw_resume.pass.cpp +++ b/libunwind/test/unw_resume.pass.cpp @@ -15,7 +15,7 @@ #include <libunwind.h> -void test_unw_resume() { +__attribute__((noinline)) void test_unw_resume() { unw_context_t context; unw_cursor_t cursor; diff --git a/libunwind/test/unwind_leaffunction.pass.cpp b/libunwind/test/unwind_leaffunction.pass.cpp index 8c9912e3c38680b..bcfb38f11f3fbde 100644 --- a/libunwind/test/unwind_leaffunction.pass.cpp +++ b/libunwind/test/unwind_leaffunction.pass.cpp @@ -28,7 +28,7 @@ _Unwind_Reason_Code frame_handler(struct _Unwind_Context* ctx, void* arg) { (void)arg; Dl_info info = { 0, 0, 0, 0 }; - // Unwind until the main is reached, above frames deeped on the platform and + // Unwind until the main is reached, above frames depend on the platform and // architecture. if (dladdr(reinterpret_cast<void *>(_Unwind_GetIP(ctx)), &info) && info.dli_sname && !strcmp("main", info.dli_sname)) { @@ -43,18 +43,22 @@ void signal_handler(int signum) { _Exit(-1); } -__attribute__((noinline)) void crashing_leaf_func(void) { +__attribute__((noinline)) void crashing_leaf_func(int do_trap) { // libunwind searches for the address before the return address which points - // to the trap instruction. NOP guarantees the trap instruction is not the - // first instruction of the function. - // We should keep this here for other unwinders that also decrement pc. - __asm__ __volatile__("nop"); - __builtin_trap(); + // to the trap instruction. We make the trap conditional and prevent inlining + // of the function to ensure that the compiler doesn't remove the `ret` instruction + // altogether. + // + // It's also important that the trap instruction isn't the first instruction in the + // function (which it isn't because of the branch) for other unwinders that also + // decrement pc. + if (do_trap) + __builtin_trap(); } int main(int, char**) { signal(SIGTRAP, signal_handler); signal(SIGILL, signal_handler); - crashing_leaf_func(); + crashing_leaf_func(1); return -2; } >From 56626ea2e9f978ee3625da824f0e11d6b5bf82d1 Mon Sep 17 00:00:00 2001 From: Louis Dionne <ldionn...@gmail.com> Date: Fri, 17 Nov 2023 16:44:28 -0500 Subject: [PATCH 2/4] Fix formatting --- libunwind/test/libunwind_02.pass.cpp | 12 +++++++----- libunwind/test/unwind_leaffunction.pass.cpp | 10 +++++----- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/libunwind/test/libunwind_02.pass.cpp b/libunwind/test/libunwind_02.pass.cpp index 710325e42dc0b2e..9fd8e5d7159c968 100644 --- a/libunwind/test/libunwind_02.pass.cpp +++ b/libunwind/test/libunwind_02.pass.cpp @@ -21,7 +21,8 @@ #define EXPECTED_NUM_FRAMES 50 #define NUM_FRAMES_UPPER_BOUND 100 -__attribute__((noinline)) _Unwind_Reason_Code callback(_Unwind_Context *context, void *cnt) { +__attribute__((noinline)) _Unwind_Reason_Code callback(_Unwind_Context *context, + void *cnt) { (void)context; int *i = (int *)cnt; ++*i; @@ -39,10 +40,11 @@ __attribute__((noinline)) void test_backtrace() { } } -// These functions are effectively the same, but we have to be careful to avoid unwanted -// optimizations that would mess with the number of frames we expect. Surprisingly, -// slapping `noinline` is not sufficient -- we also have to avoid writing the function -// in a way that the compiler can easily spot tail recursion. +// These functions are effectively the same, but we have to be careful to avoid +// unwanted optimizations that would mess with the number of frames we expect. +// Surprisingly, slapping `noinline` is not sufficient -- we also have to avoid +// writing the function in a way that the compiler can easily spot tail +// recursion. __attribute__((noinline)) int test1(int i); __attribute__((noinline)) int test2(int i); diff --git a/libunwind/test/unwind_leaffunction.pass.cpp b/libunwind/test/unwind_leaffunction.pass.cpp index bcfb38f11f3fbde..112a5968247a42d 100644 --- a/libunwind/test/unwind_leaffunction.pass.cpp +++ b/libunwind/test/unwind_leaffunction.pass.cpp @@ -46,12 +46,12 @@ void signal_handler(int signum) { __attribute__((noinline)) void crashing_leaf_func(int do_trap) { // libunwind searches for the address before the return address which points // to the trap instruction. We make the trap conditional and prevent inlining - // of the function to ensure that the compiler doesn't remove the `ret` instruction - // altogether. + // of the function to ensure that the compiler doesn't remove the `ret` + // instruction altogether. // - // It's also important that the trap instruction isn't the first instruction in the - // function (which it isn't because of the branch) for other unwinders that also - // decrement pc. + // It's also important that the trap instruction isn't the first instruction + // in the function (which it isn't because of the branch) for other unwinders + // that also decrement pc. if (do_trap) __builtin_trap(); } >From bc5f12b0c98e767a0a969d1495b93f7b82199a4f Mon Sep 17 00:00:00 2001 From: Louis Dionne <ldionn...@gmail.com> Date: Mon, 20 Nov 2023 12:00:23 -0500 Subject: [PATCH 3/4] Remove re-implementation of DoNotOptimize --- .../support.dynamic/libcpp_deallocate.sh.cpp | 17 ++++++----- .../new.size.replace.indirect.pass.cpp | 3 +- .../new.size.replace.pass.cpp | 3 +- .../new.size_align.replace.indirect.pass.cpp | 7 ++--- ...ze_align_nothrow.replace.indirect.pass.cpp | 7 ++--- .../new.size_align_nothrow.replace.pass.cpp | 7 ++--- ...new.size_nothrow.replace.indirect.pass.cpp | 3 +- .../new.size_nothrow.replace.pass.cpp | 3 +- .../new.size.replace.pass.cpp | 3 +- ...ze_align_nothrow.replace.indirect.pass.cpp | 7 ++--- ...new.size_nothrow.replace.indirect.pass.cpp | 3 +- libcxx/test/support/do_not_optimize.h | 28 ------------------- libcxx/test/support/test_macros.h | 6 ++++ 13 files changed, 32 insertions(+), 65 deletions(-) delete mode 100644 libcxx/test/support/do_not_optimize.h diff --git a/libcxx/test/libcxx/language.support/support.dynamic/libcpp_deallocate.sh.cpp b/libcxx/test/libcxx/language.support/support.dynamic/libcpp_deallocate.sh.cpp index 6e6229b752a7a6e..267f87bd3f6f89b 100644 --- a/libcxx/test/libcxx/language.support/support.dynamic/libcpp_deallocate.sh.cpp +++ b/libcxx/test/libcxx/language.support/support.dynamic/libcpp_deallocate.sh.cpp @@ -34,7 +34,6 @@ #include <cstdlib> #include <new> -#include "do_not_optimize.h" #include "test_macros.h" TEST_DIAGNOSTIC_PUSH @@ -188,13 +187,13 @@ void test_allocator_and_new_match() { stats.reset(); #if defined(NO_SIZE) && defined(NO_ALIGN) { - int* x = support::do_not_optimize(new int(42)); + int* x = DoNotOptimize(new int(42)); delete x; assert(stats.expect_plain()); } stats.reset(); { - AlignedType* a = support::do_not_optimize(new AlignedType()); + AlignedType* a = DoNotOptimize(new AlignedType()); delete a; assert(stats.expect_plain()); } @@ -203,14 +202,14 @@ void test_allocator_and_new_match() { stats.reset(); #if TEST_STD_VER >= 11 { - int* x = support::do_not_optimize(new int(42)); + int* x = DoNotOptimize(new int(42)); delete x; assert(stats.expect_plain()); } #endif stats.reset(); { - AlignedType* a = support::do_not_optimize(new AlignedType()); + AlignedType* a = DoNotOptimize(new AlignedType()); delete a; assert(stats.expect_align(TEST_ALIGNOF(AlignedType))); } @@ -218,13 +217,13 @@ void test_allocator_and_new_match() { #elif defined(NO_ALIGN) stats.reset(); { - int* x = support::do_not_optimize(new int(42)); + int* x = DoNotOptimize(new int(42)); delete x; assert(stats.expect_size(sizeof(int))); } stats.reset(); { - AlignedType* a = support::do_not_optimize(new AlignedType()); + AlignedType* a = DoNotOptimize(new AlignedType()); delete a; assert(stats.expect_size(sizeof(AlignedType))); } @@ -232,13 +231,13 @@ void test_allocator_and_new_match() { #else stats.reset(); { - int* x = support::do_not_optimize(new int(42)); + int* x = DoNotOptimize(new int(42)); delete x; assert(stats.expect_size(sizeof(int))); } stats.reset(); { - AlignedType* a = support::do_not_optimize(new AlignedType()); + AlignedType* a = DoNotOptimize(new AlignedType()); delete a; assert(stats.expect_size_align(sizeof(AlignedType), TEST_ALIGNOF(AlignedType))); diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.replace.indirect.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.replace.indirect.pass.cpp index 13f6217c521fa8f..daedbb38d05cce5 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.replace.indirect.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.replace.indirect.pass.cpp @@ -20,7 +20,6 @@ #include <cassert> #include <limits> -#include "do_not_optimize.h" #include "test_macros.h" int new_called = 0; @@ -41,7 +40,7 @@ void operator delete(void* p) TEST_NOEXCEPT { int main(int, char**) { new_called = delete_called = 0; - int* x = support::do_not_optimize(new int[3]); + int* x = DoNotOptimize(new int[3]); assert(x != nullptr); ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_called == 1); diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.replace.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.replace.pass.cpp index 9b3d39986484ddd..5fa3d72b781683d 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.replace.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.replace.pass.cpp @@ -19,7 +19,6 @@ #include <cassert> #include <limits> -#include "do_not_optimize.h" #include "test_macros.h" int new_called = 0; @@ -39,7 +38,7 @@ void operator delete[](void* p) TEST_NOEXCEPT { int main(int, char**) { new_called = delete_called = 0; - int* x = support::do_not_optimize(new int[3]); + int* x = DoNotOptimize(new int[3]); assert(x != nullptr); ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_called == 1); diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align.replace.indirect.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align.replace.indirect.pass.cpp index 014951f50b7eb7e..66cbb4b9c8eb614 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align.replace.indirect.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align.replace.indirect.pass.cpp @@ -26,7 +26,6 @@ #include <cassert> #include <limits> -#include "do_not_optimize.h" #include "test_macros.h" #include "../types.h" @@ -52,7 +51,7 @@ int main(int, char**) { // Test with an overaligned type { new_called = delete_called = 0; - OverAligned* x = support::do_not_optimize(new OverAligned[3]); + OverAligned* x = DoNotOptimize(new OverAligned[3]); ASSERT_WITH_OPERATOR_NEW_FALLBACKS(static_cast<void*>(x) == DummyData); ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_called == 1); @@ -63,7 +62,7 @@ int main(int, char**) { // Test with a type that is right on the verge of being overaligned { new_called = delete_called = 0; - MaxAligned* x = support::do_not_optimize(new MaxAligned[3]); + MaxAligned* x = DoNotOptimize(new MaxAligned[3]); assert(x != nullptr); assert(new_called == 0); @@ -74,7 +73,7 @@ int main(int, char**) { // Test with a type that is clearly not overaligned { new_called = delete_called = 0; - int* x = support::do_not_optimize(new int[3]); + int* x = DoNotOptimize(new int[3]); assert(x != nullptr); assert(new_called == 0); diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align_nothrow.replace.indirect.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align_nothrow.replace.indirect.pass.cpp index 99926b876a03825..df8a651932cef1b 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align_nothrow.replace.indirect.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align_nothrow.replace.indirect.pass.cpp @@ -26,7 +26,6 @@ #include <cassert> #include <limits> -#include "do_not_optimize.h" #include "test_macros.h" #include "../types.h" @@ -52,7 +51,7 @@ int main(int, char**) { // Test with an overaligned type { new_called = delete_called = 0; - OverAligned* x = support::do_not_optimize(new (std::nothrow) OverAligned[3]); + OverAligned* x = DoNotOptimize(new (std::nothrow) OverAligned[3]); ASSERT_WITH_OPERATOR_NEW_FALLBACKS(static_cast<void*>(x) == DummyData); ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_called == 1); @@ -63,7 +62,7 @@ int main(int, char**) { // Test with a type that is right on the verge of being overaligned { new_called = delete_called = 0; - MaxAligned* x = support::do_not_optimize(new (std::nothrow) MaxAligned[3]); + MaxAligned* x = DoNotOptimize(new (std::nothrow) MaxAligned[3]); assert(x != nullptr); assert(new_called == 0); @@ -74,7 +73,7 @@ int main(int, char**) { // Test with a type that is clearly not overaligned { new_called = delete_called = 0; - int* x = support::do_not_optimize(new (std::nothrow) int[3]); + int* x = DoNotOptimize(new (std::nothrow) int[3]); assert(x != nullptr); assert(new_called == 0); diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align_nothrow.replace.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align_nothrow.replace.pass.cpp index cd8af782f9726d0..b984e8cf0a43ae5 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align_nothrow.replace.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align_nothrow.replace.pass.cpp @@ -23,7 +23,6 @@ #include <cassert> #include <limits> -#include "do_not_optimize.h" #include "test_macros.h" #include "../types.h" @@ -49,7 +48,7 @@ int main(int, char**) { // Test with an overaligned type { new_nothrow_called = delete_called = 0; - OverAligned* x = support::do_not_optimize(new (std::nothrow) OverAligned[3]); + OverAligned* x = DoNotOptimize(new (std::nothrow) OverAligned[3]); assert(static_cast<void*>(x) == DummyData); ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_nothrow_called == 1); @@ -60,7 +59,7 @@ int main(int, char**) { // Test with a type that is right on the verge of being overaligned { new_nothrow_called = delete_called = 0; - MaxAligned* x = support::do_not_optimize(new (std::nothrow) MaxAligned[3]); + MaxAligned* x = DoNotOptimize(new (std::nothrow) MaxAligned[3]); assert(x != nullptr); assert(new_nothrow_called == 0); @@ -71,7 +70,7 @@ int main(int, char**) { // Test with a type that is clearly not overaligned { new_nothrow_called = delete_called = 0; - int* x = support::do_not_optimize(new (std::nothrow) int[3]); + int* x = DoNotOptimize(new (std::nothrow) int[3]); assert(x != nullptr); assert(new_nothrow_called == 0); diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_nothrow.replace.indirect.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_nothrow.replace.indirect.pass.cpp index 8b0d801acd1fcc6..eb14e3d15db2f2a 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_nothrow.replace.indirect.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_nothrow.replace.indirect.pass.cpp @@ -24,7 +24,6 @@ #include <cstdlib> #include <cassert> -#include "do_not_optimize.h" #include "test_macros.h" int new_called = 0; @@ -45,7 +44,7 @@ void operator delete(void* p) TEST_NOEXCEPT { int main(int, char**) { new_called = delete_called = 0; - int* x = support::do_not_optimize(new (std::nothrow) int[3]); + int* x = DoNotOptimize(new (std::nothrow) int[3]); assert(x != nullptr); ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_called == 1); diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_nothrow.replace.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_nothrow.replace.pass.cpp index c9e4942d8153166..2b8918276d77d6c 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_nothrow.replace.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_nothrow.replace.pass.cpp @@ -18,7 +18,6 @@ #include <cstdlib> #include <cassert> -#include "do_not_optimize.h" #include "test_macros.h" int new_nothrow_called = 0; @@ -36,7 +35,7 @@ void operator delete[](void* p) TEST_NOEXCEPT { int main(int, char**) { new_nothrow_called = delete_called = 0; - int* x = support::do_not_optimize(new (std::nothrow) int[3]); + int* x = DoNotOptimize(new (std::nothrow) int[3]); assert(x != nullptr); ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_nothrow_called == 1); diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size.replace.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size.replace.pass.cpp index c62268c39027c8d..a345559e832c69a 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size.replace.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size.replace.pass.cpp @@ -17,7 +17,6 @@ #include <cstdlib> #include <cassert> -#include "do_not_optimize.h" #include "test_macros.h" int new_called = 0; @@ -37,7 +36,7 @@ void operator delete(void* p) TEST_NOEXCEPT { int main(int, char**) { new_called = delete_called = 0; - int* x = support::do_not_optimize(new int(3)); + int* x = DoNotOptimize(new int(3)); assert(x != nullptr); ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_called == 1); diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_align_nothrow.replace.indirect.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_align_nothrow.replace.indirect.pass.cpp index 1c42cdbb50db6b2..a68cdab54528c27 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_align_nothrow.replace.indirect.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_align_nothrow.replace.indirect.pass.cpp @@ -25,7 +25,6 @@ #include <cassert> #include <limits> -#include "do_not_optimize.h" #include "test_macros.h" #include "../types.h" @@ -51,7 +50,7 @@ int main(int, char**) { // Test with an overaligned type { new_called = delete_called = 0; - OverAligned* x = support::do_not_optimize(new (std::nothrow) OverAligned); + OverAligned* x = DoNotOptimize(new (std::nothrow) OverAligned); ASSERT_WITH_OPERATOR_NEW_FALLBACKS(static_cast<void*>(x) == DummyData); ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_called == 1); @@ -62,7 +61,7 @@ int main(int, char**) { // Test with a type that is right on the verge of being overaligned { new_called = delete_called = 0; - MaxAligned* x = support::do_not_optimize(new (std::nothrow) MaxAligned); + MaxAligned* x = DoNotOptimize(new (std::nothrow) MaxAligned); assert(x != nullptr); assert(new_called == 0); @@ -73,7 +72,7 @@ int main(int, char**) { // Test with a type that is clearly not overaligned { new_called = delete_called = 0; - int* x = support::do_not_optimize(new (std::nothrow) int); + int* x = DoNotOptimize(new (std::nothrow) int); assert(x != nullptr); assert(new_called == 0); diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_nothrow.replace.indirect.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_nothrow.replace.indirect.pass.cpp index e5f91ad44fc0cf3..c72e99d387e1bd2 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_nothrow.replace.indirect.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_nothrow.replace.indirect.pass.cpp @@ -19,7 +19,6 @@ #include <cstdlib> #include <cassert> -#include "do_not_optimize.h" #include "test_macros.h" int new_called = 0; @@ -40,7 +39,7 @@ void operator delete(void* p) TEST_NOEXCEPT { int main(int, char**) { new_called = delete_called = 0; - int* x = support::do_not_optimize(new (std::nothrow) int(3)); + int* x = DoNotOptimize(new (std::nothrow) int(3)); assert(x != nullptr); ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_called == 1); diff --git a/libcxx/test/support/do_not_optimize.h b/libcxx/test/support/do_not_optimize.h deleted file mode 100644 index 542851a8ea6ae2d..000000000000000 --- a/libcxx/test/support/do_not_optimize.h +++ /dev/null @@ -1,28 +0,0 @@ -// -*- C++ -*- -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef SUPPORT_DO_NOT_OPTIMIZE_H -#define SUPPORT_DO_NOT_OPTIMIZE_H - -#include "test_macros.h" - -namespace support { -// This function can be used to hide some objects from compiler optimizations. -// -// For example, this is useful to hide the result of a call to `new` and ensure -// that the compiler doesn't elide the call to new/delete. Otherwise, elliding -// calls to new/delete is allowed by the Standard and compilers actually do it -// when optimizations are enabled. -template <class T> -TEST_CONSTEXPR __attribute__((noinline)) T* do_not_optimize(T* ptr) TEST_NOEXCEPT { - return ptr; -} -} // namespace support - -#endif // SUPPORT_DO_NOT_OPTIMIZE_H diff --git a/libcxx/test/support/test_macros.h b/libcxx/test/support/test_macros.h index f3c6d8080ff6d83..a38772a6eb5c807 100644 --- a/libcxx/test/support/test_macros.h +++ b/libcxx/test/support/test_macros.h @@ -274,6 +274,12 @@ struct is_same<T, T> { enum {value = 1}; }; #endif #if defined(__GNUC__) || defined(__clang__) +// This function can be used to hide some objects from compiler optimizations. +// +// For example, this is useful to hide the result of a call to `new` and ensure +// that the compiler doesn't elide the call to new/delete. Otherwise, elliding +// calls to new/delete is allowed by the Standard and compilers actually do it +// when optimizations are enabled. template <class Tp> inline void DoNotOptimize(Tp const& value) { >From 1b132d6d9ba47681ebd8a86b8e4e53fe68a6b5b4 Mon Sep 17 00:00:00 2001 From: Louis Dionne <ldionn...@gmail.com> Date: Fri, 1 Dec 2023 11:30:16 -0500 Subject: [PATCH 4/4] Fix DoNotOptimize --- libcxx/test/support/test_macros.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libcxx/test/support/test_macros.h b/libcxx/test/support/test_macros.h index a38772a6eb5c807..9d7f2978b9489b5 100644 --- a/libcxx/test/support/test_macros.h +++ b/libcxx/test/support/test_macros.h @@ -281,18 +281,19 @@ struct is_same<T, T> { enum {value = 1}; }; // calls to new/delete is allowed by the Standard and compilers actually do it // when optimizations are enabled. template <class Tp> -inline -void DoNotOptimize(Tp const& value) { +inline Tp const& DoNotOptimize(Tp const& value) { asm volatile("" : : "r,m"(value) : "memory"); + return value; } template <class Tp> -inline void DoNotOptimize(Tp& value) { +inline Tp& DoNotOptimize(Tp& value) { #if defined(__clang__) asm volatile("" : "+r,m"(value) : : "memory"); #else asm volatile("" : "+m,r"(value) : : "memory"); #endif + return value; } #else #include <intrin.h> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits