diff --git a/libcxxabi/test/vendor/ibm/cond_reg_restore.pass.cpp b/libcxxabi/test/vendor/ibm/cond_reg_restore.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxxabi/test/vendor/ibm/cond_reg_restore.pass.cpp @@ -0,0 +1,44 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// Check that the condition register is restored properly during unwinding +// on AIX. Option -O3 is required so that the compiler will re-use the value +// in the condition register instead of re-evaluating the condition expression. + +// REQUIRES: target=powerpc{{(64)?}}-ibm-aix +// ADDITIONAL_COMPILE_FLAGS: -O3 +// UNSUPPORTED: no-exceptions + +#include +#include + +int __attribute__((noinline)) test2(int i) { + // The inline assembly forces the prologue/epilogue to save/restore the + // condition register. + asm volatile("nop" : : : "cr2"); + if (i > 3) { + throw i; + } + srand(i); + return rand() + i; +} + +void __attribute__((noinline)) test(int argc, const char **argv) { + int a = atoi(argv[1]); + int b = atoi(argv[2]); + try { + test2(a < b ? argc : b); + } catch (int num) { + assert(!(a < b)); + } +} +int main(int, char**) { + const char *av[]={"a.out", "12", "10"}; + test(4, av); + return 0; +} diff --git a/libcxxabi/test/vendor/ibm/vec_reg_restore.pass.cpp b/libcxxabi/test/vendor/ibm/vec_reg_restore.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxxabi/test/vendor/ibm/vec_reg_restore.pass.cpp @@ -0,0 +1,102 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// Check that the PowerPC vector registers are restored properly during +// unwinding. Option -mabi=vec-extabi is required to compile the test case. + +// REQUIRES: target=powerpc{{(64)?}}-ibm-aix +// ADDITIONAL_COMPILE_FLAGS: -mabi=vec-extabi +// UNSUPPORTED: no-exceptions + +// AIX does not support the eh_frame section. Instead, the traceback table +// located at the end of each function provides the information for stack +// unwinding. Non-volatile GRs, FRs, and VRs clobbered by the function are +// saved on the stack and the numbers of saved registers are available in the +// traceback table. Registers are saved from high number to low consecutively, +// e.g., if n VRs are saved, the order on the stack will be VR63, VR62, ..., +// VR63-n+1. This test cases checks the unwinder gets to the location of saved +// VRs which should be 16-byte aligned and restores them correctly based on +// the number specified in the traceback table. To simplify, only the 2 high +// numbered VRs are checked. Because PowerPC CPUs do not have instructions to +// assign a literal value to a VR directly until Power10, the value is +// assigned to a GR and then from the GR to a VR in the code. +// + +#include +#include + +int __attribute__((noinline)) test2(int i) +{ + if (i > 3) + throw i; + srand(i); + return rand(); +} + +int __attribute__((noinline)) test(int i) { + // Clobber VR63 and VR62 in the function body. + // Set VR63=100. + asm volatile("li 30, 100\n\t" + "mtvsrd 63, 30\n\t" + : + : + : "v31", "r30"); + // Set VR62=200. + asm volatile("li 29, 200\n\t" + "mtvsrd 62, 29\n\t" + : + : + : "v30", "r29"); + return test2(i); +} + +// Return the value of VR63 in 'output'. +#define getFirstValue(output) \ + asm volatile( "mfvsrd 4, 63\n\t" \ + "std 4, %[d]" \ + : [d] "=rm"(output) \ + : \ + : ) +// Return the value of VR62 in 'output'. +#define getSecondValue(output) \ + asm volatile( "mfvsrd 4, 62\n\t" \ + "std 4, %[d]" \ + : [d] "=rm"(output) \ + : \ + : ) + +int main(int, char**) { + // Set VR63=1. + asm volatile("li 30, 1\n\t" + "mtvsrd 63, 30\n\t" + : + : + : "v31", "r30"); + // Set VR62=1. + asm volatile("li 29, 2\n\t" + "mtvsrd 62, 29\n\t" + : + : + : "v30", "r29"); + long long old; + long long old2; + getFirstValue(old); + getSecondValue(old2); + try { + test(4); + } catch (int num) { + long long new_value; + long long new_value2; + getFirstValue(new_value); + getSecondValue(new_value2); + // If the unwinder restores VR63 and VR62 correctly, they should contain + // 1 and 2 respectively instead of 100 and 200. + assert(old == new_value && old2 == new_value2); + } + return 0; +}