2 * Copyright (c) 2013 The Native Client Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
7 #include "native_client/tests/toolchain/eh_helper.h"
12 // Test that EH stack unwinding works when callee-saved floating point
13 // registers may be saved (e.g., on ARM).
14 // Also test that the callee-saved registers are restored during
15 // stack unwinding, for use in a catch-statement.
19 // Make a float x 4, without including arch-specific headers.
20 typedef float v4sf __attribute__ ((__vector_size__(16)));
22 // Make it a union to help w/ accessing an individual element.
28 // Make some volatile constants to trick the optimizer.
29 volatile double kZero = 0.0;
30 volatile double kOne = 1.0;
31 volatile double kPiOver2 = M_PI_2;
32 volatile double kE = M_E;
33 volatile Vec_4_f kVOnes __attribute__((aligned(16))) = {
34 { (float)kOne, (float)kOne, (float)kOne, (float)kOne }
37 // Make a function with roughly this structure:
38 // x, y, z = Heavy-Floating-Point-Compute;
42 // That makes it likely that x, y, z use callee-saved registers, instead of
43 // restoring values from the stack after the call.
44 void __attribute__((noinline)) outer(
45 double x, double y, double z, double w);
46 void outer(double x, double y, double z, double w) {
47 // Assume that the caller gives us appropriate values so that these
48 // computations give 0 as the result.
49 double should_be_zero1 = round(sqrt(x));
50 double should_be_zero2 = round(cos(y));
51 double should_be_zero3 = round(sin(z));
52 double should_be_zero4 = round(log(w));
53 double should_be_zero;
54 Vec_4_f v_should_be_ones __attribute__((aligned(16))),
55 v_will_be_zeros __attribute__((aligned(16)));
56 v_should_be_ones.v = kVOnes.v;
57 // Start v_will_be_zeros as all ones.
58 // Then do v_will_be_zeros = <1...> * <1...> - <1...>.
59 v_will_be_zeros.v = kVOnes.v;
61 v_will_be_zeros.v * v_should_be_ones.v - v_should_be_ones.v;
62 // Function call to make it worth using callee-saved regs.
63 printf("Should be zero: %f, %f, %f, %f, %f\n",
64 should_be_zero1, should_be_zero2, should_be_zero3, should_be_zero4,
65 v_will_be_zeros.elems[0]);
66 if (should_be_zero1 > should_be_zero2)
67 should_be_zero = should_be_zero1;
68 else if (should_be_zero2 > should_be_zero3)
69 should_be_zero = should_be_zero2;
70 else if (should_be_zero3 > should_be_zero4)
71 should_be_zero = should_be_zero3;
73 should_be_zero = should_be_zero4;
74 next_step(static_cast<int>(3 - should_be_zero));
75 if (v_will_be_zeros.elems[0] > v_will_be_zeros.elems[1])
76 throw static_cast<int>(v_will_be_zeros.elems[0]);
77 else if (v_will_be_zeros.elems[1] > v_will_be_zeros.elems[2])
78 throw static_cast<int>(v_will_be_zeros.elems[1]);
79 else if (v_will_be_zeros.elems[2] > v_will_be_zeros.elems[3])
80 throw static_cast<int>(v_will_be_zeros.elems[2]);
82 throw static_cast<int>(v_will_be_zeros.elems[3]);
89 explicit B(double should_be_one) {
90 next_step(static_cast<int>(5 * should_be_one));
92 ~B() { next_step(7); }
95 void __attribute__((noinline)) middle(int never_55);
96 void middle(int never_55) {
97 double should_be_one1 = sqrt(kOne) * cos(kZero);
98 double should_be_one2 = sin(kPiOver2) * log(kE);
99 Vec_4_f v_should_be_ones1 __attribute__((aligned(16))),
100 v_should_be_ones2 __attribute__((aligned(16)));
101 v_should_be_ones1.v = kVOnes.v;
102 v_should_be_ones2.v = kVOnes.v;
103 v_should_be_ones1.v = v_should_be_ones1.v * v_should_be_ones2.v;
104 printf("Should be one: %f, %f, %f\n",
105 should_be_one1, should_be_one2, v_should_be_ones1.elems[0]);
107 // Function call to make it worth using callee-saved regs.
108 outer(kZero, kPiOver2, kZero, kOne);
112 printf("Should still be one: %f, %f, %f\n",
113 should_be_one1, should_be_one2, v_should_be_ones1.elems[0]);
115 if (should_be_one1 > should_be_one2) {
116 throw B(should_be_one1);
117 } else if (should_be_one2 > v_should_be_ones1.elems[0]) {
118 throw B(should_be_one2);
120 throw B(v_should_be_ones1.elems[0]);
126 int main(int argc, char* argv[]) {
127 double should_be_e = kE;
128 double should_be_pi_2 = kPiOver2;
129 double should_be_63 = sqrt(kOne) * cos(kZero) * 63;
130 double should_be_127 = sin(kPiOver2) * log(kE) * 127;
136 fprintf(stderr, "should_be_e=%f, should_be_pi_2=%f, "
137 "should_be_63=%f, shouldbe_127=%f\n",
138 should_be_e, should_be_pi_2, should_be_63, should_be_127);
139 assert(should_be_e == kE);
140 assert(should_be_pi_2 == kPiOver2);
141 assert(should_be_63 == 63.0);
142 assert(should_be_127 == 127.0);