Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / native_client / tests / toolchain / eh_floating_point.cc
1 /*
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.
5  */
6
7 #include "native_client/tests/toolchain/eh_helper.h"
8
9 #include <assert.h>
10 #include <math.h>
11
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.
16
17 namespace {
18
19 // Make a float x 4, without including arch-specific headers.
20 typedef float v4sf __attribute__ ((__vector_size__(16)));
21
22 // Make it a union to help w/ accessing an individual element.
23 typedef union {
24   float elems[4];
25   v4sf v;
26 } Vec_4_f;
27
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 }
35 };
36
37 // Make a function with roughly this structure:
38 // x, y, z = Heavy-Floating-Point-Compute;
39 // call();
40 // use(x, y, z);
41 //
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;
60   v_will_be_zeros.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;
72   else
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]);
81   else
82     throw static_cast<int>(v_will_be_zeros.elems[3]);
83 }
84
85 }  // namespace
86
87 class B {
88  public:
89   explicit B(double should_be_one) {
90     next_step(static_cast<int>(5 * should_be_one));
91   }
92   ~B() { next_step(7); }
93 };
94
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]);
106   try {
107     // Function call to make it worth using callee-saved regs.
108     outer(kZero, kPiOver2, kZero, kOne);
109   } catch(int x) {
110     if (x != 0)
111       abort();
112     printf("Should still be one: %f, %f, %f\n",
113            should_be_one1, should_be_one2, v_should_be_ones1.elems[0]);
114     next_step(4);
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);
119     } else {
120       throw B(v_should_be_ones1.elems[0]);
121     }
122   }
123   abort();
124 }
125
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;
131   next_step(1);
132   try {
133     next_step(2);
134     middle(argc);
135   } catch(...) {
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);
143     next_step(6);
144   }
145   next_step(8);
146   return 55;
147 }