1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 // Check that the PowerPC vector registers are restored properly during
10 // unwinding. Option -mabi=vec-extabi is required to compile the test case.
11
12 // REQUIRES: target=powerpc{{(64)?}}-ibm-aix
13 // ADDITIONAL_COMPILE_FLAGS: -mabi=vec-extabi
14 // UNSUPPORTED: no-exceptions
15
16 // AIX does not support the eh_frame section. Instead, the traceback table
17 // located at the end of each function provides the information for stack
18 // unwinding. Non-volatile GRs, FRs, and VRs clobbered by the function are
19 // saved on the stack and the numbers of saved registers are available in the
20 // traceback table. Registers are saved from high number to low consecutively,
21 // e.g., if n VRs are saved, the order on the stack will be VR63, VR62, ...,
22 // VR63-n+1. This test cases checks the unwinder gets to the location of saved
23 // VRs which should be 16-byte aligned and restores them correctly based on
24 // the number specified in the traceback table. To simplify, only the 2 high
25 // numbered VRs are checked. Because PowerPC CPUs do not have instructions to
26 // assign a literal value to a VR directly until Power10, the value is
27 // assigned to a GR and then from the GR to a VR in the code.
28 //
29
30 #include <cstdlib>
31 #include <cassert>
32
test2(int i)33 int __attribute__((noinline)) test2(int i)
34 {
35 if (i > 3)
36 throw i;
37 srand(i);
38 return rand();
39 }
40
test(int i)41 int __attribute__((noinline)) test(int i) {
42 // Clobber VR63 and VR62 in the function body.
43 // Set VR63=100.
44 asm volatile("li 30, 100\n\t"
45 "mtvsrd 63, 30\n\t"
46 :
47 :
48 : "v31", "r30");
49 // Set VR62=200.
50 asm volatile("li 29, 200\n\t"
51 "mtvsrd 62, 29\n\t"
52 :
53 :
54 : "v30", "r29");
55 return test2(i);
56 }
57
58 // Return the value of VR63 in 'output'.
59 #define getFirstValue(output) \
60 asm volatile( "mfvsrd 4, 63\n\t" \
61 "std 4, %[d]" \
62 : [d] "=rm"(output) \
63 : \
64 : )
65 // Return the value of VR62 in 'output'.
66 #define getSecondValue(output) \
67 asm volatile( "mfvsrd 4, 62\n\t" \
68 "std 4, %[d]" \
69 : [d] "=rm"(output) \
70 : \
71 : )
72
main(int,char **)73 int main(int, char**) {
74 // Set VR63=1.
75 asm volatile("li 30, 1\n\t"
76 "mtvsrd 63, 30\n\t"
77 :
78 :
79 : "v31", "r30");
80 // Set VR62=1.
81 asm volatile("li 29, 2\n\t"
82 "mtvsrd 62, 29\n\t"
83 :
84 :
85 : "v30", "r29");
86 long long old;
87 long long old2;
88 getFirstValue(old);
89 getSecondValue(old2);
90 try {
91 test(4);
92 } catch (int num) {
93 long long new_value;
94 long long new_value2;
95 getFirstValue(new_value);
96 getSecondValue(new_value2);
97 // If the unwinder restores VR63 and VR62 correctly, they should contain
98 // 1 and 2 respectively instead of 100 and 200.
99 assert(old == new_value && old2 == new_value2);
100 }
101 return 0;
102 }
103