summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLouis Dionne <ldionne.2@gmail.com>2024-01-09 10:39:14 -0500
committerGitHub <noreply@github.com>2024-01-09 10:39:14 -0500
commitca06c330fd07f05e65a638892c32ca1474d47b5e (patch)
tree7bec5b463890ce5ecc06654a7484fe7f97ed9745
parent07c9189fcc063bdf6219d2733843c89cde3991e1 (diff)
[libc++] Allow running the test suite with optimizations (#68753)
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
-rw-r--r--.github/workflows/libcxx-build-and-test.yaml1
-rw-r--r--libcxx/cmake/caches/Generic-optimized-speed.cmake4
-rw-r--r--libcxx/test/libcxx/depr/depr.default.allocator/allocator.members/allocate.cxx2a.pass.cpp2
-rw-r--r--libcxx/test/libcxx/language.support/support.dynamic/libcpp_deallocate.sh.cpp16
-rw-r--r--libcxx/test/std/experimental/simd/simd.class/simd_ctor_conversion.pass.cpp4
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.member/path.assign/move.pass.cpp2
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/move.pass.cpp2
-rw-r--r--libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.replace.indirect.pass.cpp2
-rw-r--r--libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.replace.pass.cpp2
-rw-r--r--libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align.replace.indirect.pass.cpp6
-rw-r--r--libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align_nothrow.replace.indirect.pass.cpp6
-rw-r--r--libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align_nothrow.replace.pass.cpp6
-rw-r--r--libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_nothrow.replace.indirect.pass.cpp2
-rw-r--r--libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_nothrow.replace.pass.cpp2
-rw-r--r--libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size.replace.pass.cpp2
-rw-r--r--libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_align_nothrow.replace.indirect.pass.cpp6
-rw-r--r--libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_nothrow.replace.indirect.pass.cpp2
-rw-r--r--libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.alg/swap.pass.cpp16
-rw-r--r--libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/F.pass.cpp2
-rw-r--r--libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/copy_assign.pass.cpp8
-rw-r--r--libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/copy_move.pass.cpp8
-rw-r--r--libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/nullptr_t_assign.pass.cpp2
-rw-r--r--libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.mod/swap.pass.cpp12
-rw-r--r--libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/make_shared.pass.cpp4
-rw-r--r--libcxx/test/support/count_new.h5
-rw-r--r--libcxx/test/support/test_macros.h16
-rwxr-xr-xlibcxx/utils/ci/run-buildbot5
-rw-r--r--libcxx/utils/libcxx/test/params.py36
-rw-r--r--libunwind/test/libunwind_02.pass.cpp28
-rw-r--r--libunwind/test/unw_resume.pass.cpp2
-rw-r--r--libunwind/test/unwind_leaffunction.pass.cpp20
31 files changed, 157 insertions, 74 deletions
diff --git a/.github/workflows/libcxx-build-and-test.yaml b/.github/workflows/libcxx-build-and-test.yaml
index 3fd49541fd7c..985790a0ee23 100644
--- a/.github/workflows/libcxx-build-and-test.yaml
+++ b/.github/workflows/libcxx-build-and-test.yaml
@@ -161,6 +161,7 @@ jobs:
'generic-no-unicode',
'generic-no-wide-characters',
'generic-no-rtti',
+ '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
diff --git a/libcxx/cmake/caches/Generic-optimized-speed.cmake b/libcxx/cmake/caches/Generic-optimized-speed.cmake
new file mode 100644
index 000000000000..577a5de9f34c
--- /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/depr/depr.default.allocator/allocator.members/allocate.cxx2a.pass.cpp b/libcxx/test/libcxx/depr/depr.default.allocator/allocator.members/allocate.cxx2a.pass.cpp
index da35465c5295..f2fb606ee6db 100644
--- a/libcxx/test/libcxx/depr/depr.default.allocator/allocator.members/allocate.cxx2a.pass.cpp
+++ b/libcxx/test/libcxx/depr/depr.default.allocator/allocator.members/allocate.cxx2a.pass.cpp
@@ -60,7 +60,7 @@ void test_aligned() {
{
globalMemCounter.last_new_size = 0;
globalMemCounter.last_new_align = 0;
- T* volatile ap2 = a.allocate(11, (const void*)5);
+ T* ap2 = a.allocate(11, (const void*)5);
DoNotOptimize(ap2);
assert(globalMemCounter.checkOutstandingNewEq(1));
assert(globalMemCounter.checkNewCalledEq(1));
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 fb56ce4518a7..267f87bd3f6f 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
@@ -187,13 +187,13 @@ void test_allocator_and_new_match() {
stats.reset();
#if defined(NO_SIZE) && defined(NO_ALIGN)
{
- int* x = new int(42);
+ int* x = DoNotOptimize(new int(42));
delete x;
assert(stats.expect_plain());
}
stats.reset();
{
- AlignedType* a = new AlignedType();
+ AlignedType* a = DoNotOptimize(new AlignedType());
delete a;
assert(stats.expect_plain());
}
@@ -202,14 +202,14 @@ void test_allocator_and_new_match() {
stats.reset();
#if TEST_STD_VER >= 11
{
- int* x = new int(42);
+ int* x = DoNotOptimize(new int(42));
delete x;
assert(stats.expect_plain());
}
#endif
stats.reset();
{
- AlignedType* a = new AlignedType();
+ AlignedType* a = DoNotOptimize(new AlignedType());
delete a;
assert(stats.expect_align(TEST_ALIGNOF(AlignedType)));
}
@@ -217,13 +217,13 @@ void test_allocator_and_new_match() {
#elif defined(NO_ALIGN)
stats.reset();
{
- int* x = new int(42);
+ int* x = DoNotOptimize(new int(42));
delete x;
assert(stats.expect_size(sizeof(int)));
}
stats.reset();
{
- AlignedType* a = new AlignedType();
+ AlignedType* a = DoNotOptimize(new AlignedType());
delete a;
assert(stats.expect_size(sizeof(AlignedType)));
}
@@ -231,13 +231,13 @@ void test_allocator_and_new_match() {
#else
stats.reset();
{
- int* x = new int(42);
+ int* x = DoNotOptimize(new int(42));
delete x;
assert(stats.expect_size(sizeof(int)));
}
stats.reset();
{
- AlignedType* a = 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/experimental/simd/simd.class/simd_ctor_conversion.pass.cpp b/libcxx/test/std/experimental/simd/simd.class/simd_ctor_conversion.pass.cpp
index 7ce4bed9c7db..5920d62e0e5a 100644
--- a/libcxx/test/std/experimental/simd/simd.class/simd_ctor_conversion.pass.cpp
+++ b/libcxx/test/std/experimental/simd/simd.class/simd_ctor_conversion.pass.cpp
@@ -9,6 +9,10 @@
// UNSUPPORTED: c++03, c++11, c++14
// XFAIL: target=powerpc{{.*}}le-unknown-linux-gnu
+// TODO: This test makes incorrect assumptions about floating point conversions.
+// See https://github.com/llvm/llvm-project/issues/74327.
+// XFAIL: optimization=speed
+
// <experimental/simd>
//
// [simd.class]
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 0efd9596f1c2..93295d9f6d5f 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 15782dffa7df..3c762ee676be 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 f6f586a2b547..8eaf50d538be 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
@@ -42,7 +42,7 @@ void operator delete(void* p) TEST_NOEXCEPT {
int main(int, char**) {
new_called = delete_called = 0;
- int* x = 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 29e739d8515f..9715bc9207aa 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
@@ -40,7 +40,7 @@ void operator delete[](void* p) TEST_NOEXCEPT {
int main(int, char**) {
new_called = delete_called = 0;
- int* x = 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 dcaa76a650d3..66cbb4b9c8eb 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
@@ -51,7 +51,7 @@ int main(int, char**) {
// Test with an overaligned type
{
new_called = delete_called = 0;
- OverAligned* x = 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);
@@ -62,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 MaxAligned[3];
+ MaxAligned* x = DoNotOptimize(new MaxAligned[3]);
assert(x != nullptr);
assert(new_called == 0);
@@ -73,7 +73,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 = 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 eba8a9026fa4..df8a651932ce 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
@@ -51,7 +51,7 @@ int main(int, char**) {
// Test with an overaligned type
{
new_called = delete_called = 0;
- OverAligned* x = 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);
@@ -62,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[3];
+ MaxAligned* x = DoNotOptimize(new (std::nothrow) MaxAligned[3]);
assert(x != nullptr);
assert(new_called == 0);
@@ -73,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[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 62a040e297ae..b984e8cf0a43 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
@@ -48,7 +48,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 = DoNotOptimize(new (std::nothrow) OverAligned[3]);
assert(static_cast<void*>(x) == DummyData);
ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_nothrow_called == 1);
@@ -59,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 = new (std::nothrow) MaxAligned[3];
+ MaxAligned* x = DoNotOptimize(new (std::nothrow) MaxAligned[3]);
assert(x != nullptr);
assert(new_nothrow_called == 0);
@@ -70,7 +70,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 = 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 b26eec0324af..70d891b2a82c 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
@@ -46,7 +46,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 = 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 b85e15ce64b4..2b8918276d77 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
@@ -35,7 +35,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 = 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 ab1cf5ea4644..3e0020b4f517 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
@@ -38,7 +38,7 @@ void operator delete(void* p) TEST_NOEXCEPT {
int main(int, char**) {
new_called = delete_called = 0;
- int* x = 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 4a18ad2df8f2..a68cdab54528 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
@@ -50,7 +50,7 @@ int main(int, char**) {
// Test with an overaligned type
{
new_called = delete_called = 0;
- OverAligned* x = 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);
@@ -61,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 = new (std::nothrow) MaxAligned;
+ MaxAligned* x = DoNotOptimize(new (std::nothrow) MaxAligned);
assert(x != nullptr);
assert(new_called == 0);
@@ -72,7 +72,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 = 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 35a601339ddd..64edbfd7e9af 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
@@ -41,7 +41,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 = DoNotOptimize(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 3924274190c4..97f78ac62dab 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 c1ad528254af..92409577d60d 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 75eaa55dc71e..e3bd6ef78d61 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 4a2a272ae0a3..5b3f4f10cadb 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 391e2a7434bf..b2f61fa9b68a 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 d51c35ea44fa..1723ddfd33be 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 23a904f8ae11..be7505f218cd 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 b64248501016..ef4306e520b1 100644
--- a/libcxx/test/support/count_new.h
+++ b/libcxx/test/support/count_new.h
@@ -181,6 +181,11 @@ public:
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/test_macros.h b/libcxx/test/support/test_macros.h
index ea289f0432e6..5ca4d611e1e4 100644
--- a/libcxx/test/support/test_macros.h
+++ b/libcxx/test/support/test_macros.h
@@ -283,27 +283,35 @@ 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) {
+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>
template <class Tp>
-inline void DoNotOptimize(Tp const& value) {
+inline Tp const& DoNotOptimize(Tp const& value) {
const volatile void* volatile unused = __builtin_addressof(value);
static_cast<void>(unused);
_ReadWriteBarrier();
+ return value;
}
#endif
diff --git a/libcxx/utils/ci/run-buildbot b/libcxx/utils/ci/run-buildbot
index 672d5cb70ae8..ed2bc2a14f17 100755
--- a/libcxx/utils/ci/run-buildbot
+++ b/libcxx/utils/ci/run-buildbot
@@ -522,6 +522,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 4e209901f43b..89d9f22e9dc6 100644
--- a/libcxx/utils/libcxx/test/params.py
+++ b/libcxx/utils/libcxx/test/params.py
@@ -11,7 +11,7 @@ import shlex
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 = [
@@ -88,6 +88,28 @@ def getStdFlag(cfg, 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 = [
Parameter(
@@ -119,6 +141,18 @@ DEFAULT_PARAMETERS = [
],
),
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,
+ AddFeature(f'optimization={opt}'),
+ ]),
+ ),
+ Parameter(
name="enable_modules",
choices=["none", "clang", "clang-lsv"],
type=str,
diff --git a/libunwind/test/libunwind_02.pass.cpp b/libunwind/test/libunwind_02.pass.cpp
index ea34cd54222c..9fd8e5d7159c 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
-_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 +32,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 +40,34 @@ 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 08e8d4edeaf2..2b7470b5cad0 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 8c9912e3c386..112a5968247a 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;
}