Merge "Simplify rd_pick_intra_sby_mode()"
[platform/upstream/libvpx.git] / test / register_state_check.h
1 /*
2  *  Copyright (c) 2012 The WebM project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10
11 #ifndef TEST_REGISTER_STATE_CHECK_H_
12 #define TEST_REGISTER_STATE_CHECK_H_
13
14 #include "third_party/googletest/src/include/gtest/gtest.h"
15 #include "./vpx_config.h"
16 #include "vpx/vpx_integer.h"
17
18 // ASM_REGISTER_STATE_CHECK(asm_function)
19 //   Minimally validates the environment pre & post function execution. This
20 //   variant should be used with assembly functions which are not expected to
21 //   fully restore the system state. See platform implementations of
22 //   RegisterStateCheck for details.
23 //
24 // API_REGISTER_STATE_CHECK(api_function)
25 //   Performs all the checks done by ASM_REGISTER_STATE_CHECK() and any
26 //   additional checks to ensure the environment is in a consistent state pre &
27 //   post function execution. This variant should be used with API functions.
28 //   See platform implementations of RegisterStateCheckXXX for details.
29 //
30
31 #if defined(_WIN64)
32
33 #define _WIN32_LEAN_AND_MEAN
34 #include <windows.h>
35 #include <winnt.h>
36
37 namespace testing {
38 namespace internal {
39
40 inline bool operator==(const M128A& lhs, const M128A& rhs) {
41   return (lhs.Low == rhs.Low && lhs.High == rhs.High);
42 }
43
44 }  // namespace internal
45 }  // namespace testing
46
47 namespace libvpx_test {
48
49 // Compares the state of xmm[6-15] at construction with their state at
50 // destruction. These registers should be preserved by the callee on
51 // Windows x64.
52 class RegisterStateCheck {
53  public:
54   RegisterStateCheck() { initialized_ = StoreRegisters(&pre_context_); }
55   ~RegisterStateCheck() { EXPECT_TRUE(Check()); }
56
57  private:
58   static bool StoreRegisters(CONTEXT* const context) {
59     const HANDLE this_thread = GetCurrentThread();
60     EXPECT_TRUE(this_thread != NULL);
61     context->ContextFlags = CONTEXT_FLOATING_POINT;
62     const bool context_saved = GetThreadContext(this_thread, context) == TRUE;
63     EXPECT_TRUE(context_saved) << "GetLastError: " << GetLastError();
64     return context_saved;
65   }
66
67   // Compares the register state. Returns true if the states match.
68   bool Check() const {
69     if (!initialized_) return false;
70     CONTEXT post_context;
71     if (!StoreRegisters(&post_context)) return false;
72
73     const M128A* xmm_pre = &pre_context_.Xmm6;
74     const M128A* xmm_post = &post_context.Xmm6;
75     for (int i = 6; i <= 15; ++i) {
76       EXPECT_EQ(*xmm_pre, *xmm_post) << "xmm" << i << " has been modified!";
77       ++xmm_pre;
78       ++xmm_post;
79     }
80     return !testing::Test::HasNonfatalFailure();
81   }
82
83   bool initialized_;
84   CONTEXT pre_context_;
85 };
86
87 #define ASM_REGISTER_STATE_CHECK(statement) do {  \
88   libvpx_test::RegisterStateCheck reg_check;      \
89   statement;                                      \
90 } while (false)
91
92 }  // namespace libvpx_test
93
94 #elif defined(CONFIG_SHARED) && defined(HAVE_NEON_ASM) && defined(CONFIG_VP9) \
95       && !CONFIG_SHARED && HAVE_NEON_ASM && CONFIG_VP9
96
97 extern "C" {
98 // Save the d8-d15 registers into store.
99 void vp9_push_neon(int64_t *store);
100 }
101
102 namespace libvpx_test {
103
104 // Compares the state of d8-d15 at construction with their state at
105 // destruction. These registers should be preserved by the callee on
106 // arm platform.
107 class RegisterStateCheck {
108  public:
109   RegisterStateCheck() { initialized_ = StoreRegisters(pre_store_); }
110   ~RegisterStateCheck() { EXPECT_TRUE(Check()); }
111
112  private:
113   static bool StoreRegisters(int64_t store[8]) {
114     vp9_push_neon(store);
115     return true;
116   }
117
118   // Compares the register state. Returns true if the states match.
119   bool Check() const {
120     if (!initialized_) return false;
121     int64_t post_store[8];
122     vp9_push_neon(post_store);
123     for (int i = 0; i < 8; ++i) {
124       EXPECT_EQ(pre_store_[i], post_store[i]) << "d"
125           << i + 8 << " has been modified";
126     }
127     return !testing::Test::HasNonfatalFailure();
128   }
129
130   bool initialized_;
131   int64_t pre_store_[8];
132 };
133
134 #define ASM_REGISTER_STATE_CHECK(statement) do {  \
135   libvpx_test::RegisterStateCheck reg_check;      \
136   statement;                                      \
137 } while (false)
138
139 }  // namespace libvpx_test
140
141 #else
142
143 namespace libvpx_test {
144
145 class RegisterStateCheck {};
146 #define ASM_REGISTER_STATE_CHECK(statement) statement
147
148 }  // namespace libvpx_test
149
150 #endif  // _WIN64
151
152 #if ARCH_X86 || ARCH_X86_64
153 #if defined(__GNUC__)
154
155 namespace libvpx_test {
156
157 // Checks the FPU tag word pre/post execution to ensure emms has been called.
158 class RegisterStateCheckMMX {
159  public:
160   RegisterStateCheckMMX() {
161     __asm__ volatile("fstenv %0" : "=rm"(pre_fpu_env_));
162   }
163   ~RegisterStateCheckMMX() { EXPECT_TRUE(Check()); }
164
165  private:
166   // Checks the FPU tag word pre/post execution, returning false if not cleared
167   // to 0xffff.
168   bool Check() const {
169     EXPECT_EQ(0xffff, pre_fpu_env_[4])
170         << "FPU was in an inconsistent state prior to call";
171
172     uint16_t post_fpu_env[14];
173     __asm__ volatile("fstenv %0" : "=rm"(post_fpu_env));
174     EXPECT_EQ(0xffff, post_fpu_env[4])
175         << "FPU was left in an inconsistent state after call";
176     return !testing::Test::HasNonfatalFailure();
177   }
178
179   uint16_t pre_fpu_env_[14];
180 };
181
182 #define API_REGISTER_STATE_CHECK(statement) do {  \
183   libvpx_test::RegisterStateCheckMMX reg_check;   \
184   ASM_REGISTER_STATE_CHECK(statement);            \
185 } while (false)
186
187 }  // namespace libvpx_test
188
189 #endif  // __GNUC__
190 #endif  // ARCH_X86 || ARCH_X86_64
191
192 #ifndef API_REGISTER_STATE_CHECK
193 #define API_REGISTER_STATE_CHECK ASM_REGISTER_STATE_CHECK
194 #endif
195
196 #endif  // TEST_REGISTER_STATE_CHECK_H_