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