diff options
author | Louis Dionne <ldionne.2@gmail.com> | 2024-01-09 10:39:14 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-01-09 10:39:14 -0500 |
commit | ca06c330fd07f05e65a638892c32ca1474d47b5e (patch) | |
tree | 7bec5b463890ce5ecc06654a7484fe7f97ed9745 /libunwind | |
parent | 07c9189fcc063bdf6219d2733843c89cde3991e1 (diff) | |
download | llvm-ca06c330fd07f05e65a638892c32ca1474d47b5e.zip llvm-ca06c330fd07f05e65a638892c32ca1474d47b5e.tar.gz llvm-ca06c330fd07f05e65a638892c32ca1474d47b5e.tar.bz2 |
[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
Diffstat (limited to 'libunwind')
-rw-r--r-- | libunwind/test/libunwind_02.pass.cpp | 28 | ||||
-rw-r--r-- | libunwind/test/unw_resume.pass.cpp | 2 | ||||
-rw-r--r-- | libunwind/test/unwind_leaffunction.pass.cpp | 20 |
3 files changed, 36 insertions, 14 deletions
diff --git a/libunwind/test/libunwind_02.pass.cpp b/libunwind/test/libunwind_02.pass.cpp index ea34cd5..9fd8e5d 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 08e8d4e..2b7470b 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 8c9912e..112a596 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; } |