2 * Copyright (c) 2012 The WebM project authors. All Rights Reserved.
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.
11 #ifndef VPX_TEST_REGISTER_STATE_CHECK_H_
12 #define VPX_TEST_REGISTER_STATE_CHECK_H_
14 #include "third_party/googletest/src/include/gtest/gtest.h"
15 #include "./vpx_config.h"
16 #include "vpx/vpx_integer.h"
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.
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.
31 #if defined(_WIN64) && VPX_ARCH_X86_64
35 #ifndef WIN32_LEAN_AND_MEAN
36 #define WIN32_LEAN_AND_MEAN
42 inline bool operator==(const M128A &lhs, const M128A &rhs) {
43 return (lhs.Low == rhs.Low && lhs.High == rhs.High);
46 namespace libvpx_test {
48 // Compares the state of xmm[6-15] at construction with their state at
49 // destruction. These registers should be preserved by the callee on
51 class RegisterStateCheck {
53 RegisterStateCheck() { initialized_ = StoreRegisters(&pre_context_); }
54 ~RegisterStateCheck() { Check(); }
57 static bool StoreRegisters(CONTEXT *const context) {
58 const HANDLE this_thread = GetCurrentThread();
59 EXPECT_NE(this_thread, nullptr);
60 context->ContextFlags = CONTEXT_FLOATING_POINT;
61 const bool context_saved = GetThreadContext(this_thread, context) == TRUE;
62 EXPECT_TRUE(context_saved) << "GetLastError: " << GetLastError();
66 // Compares the register state. Returns true if the states match.
68 ASSERT_TRUE(initialized_);
70 ASSERT_TRUE(StoreRegisters(&post_context));
72 const M128A *xmm_pre = &pre_context_.Xmm6;
73 const M128A *xmm_post = &post_context.Xmm6;
74 for (int i = 6; i <= 15; ++i) {
75 EXPECT_EQ(*xmm_pre, *xmm_post) << "xmm" << i << " has been modified!";
85 #define ASM_REGISTER_STATE_CHECK(statement) \
88 libvpx_test::RegisterStateCheck reg_check; \
91 _ReadWriteBarrier(); \
94 } // namespace libvpx_test
96 #elif defined(CONFIG_SHARED) && defined(HAVE_NEON_ASM) && \
97 defined(CONFIG_VP9) && !CONFIG_SHARED && HAVE_NEON_ASM && CONFIG_VP9
100 // Save the d8-d15 registers into store.
101 void vpx_push_neon(int64_t *store);
104 namespace libvpx_test {
106 // Compares the state of d8-d15 at construction with their state at
107 // destruction. These registers should be preserved by the callee on
109 class RegisterStateCheck {
111 RegisterStateCheck() { vpx_push_neon(pre_store_); }
112 ~RegisterStateCheck() { Check(); }
115 // Compares the register state. Returns true if the states match.
117 int64_t post_store[8];
118 vpx_push_neon(post_store);
119 for (int i = 0; i < 8; ++i) {
120 EXPECT_EQ(pre_store_[i], post_store[i])
121 << "d" << i + 8 << " has been modified";
125 int64_t pre_store_[8];
128 #if defined(__GNUC__)
129 #define ASM_REGISTER_STATE_CHECK(statement) \
132 libvpx_test::RegisterStateCheck reg_check; \
135 __asm__ volatile("" ::: "memory"); \
138 #define ASM_REGISTER_STATE_CHECK(statement) \
140 libvpx_test::RegisterStateCheck reg_check; \
145 } // namespace libvpx_test
149 namespace libvpx_test {
151 class RegisterStateCheck {};
152 #define ASM_REGISTER_STATE_CHECK(statement) statement
154 } // namespace libvpx_test
156 #endif // _WIN64 && VPX_ARCH_X86_64
158 #if VPX_ARCH_X86 || VPX_ARCH_X86_64
159 #if defined(__GNUC__)
161 namespace libvpx_test {
163 // Checks the FPU tag word pre/post execution to ensure emms has been called.
164 class RegisterStateCheckMMX {
166 RegisterStateCheckMMX() {
167 __asm__ volatile("fstenv %0" : "=rm"(pre_fpu_env_));
169 ~RegisterStateCheckMMX() { Check(); }
172 // Checks the FPU tag word pre/post execution, returning false if not cleared
175 EXPECT_EQ(0xffff, pre_fpu_env_[4])
176 << "FPU was in an inconsistent state prior to call";
178 uint16_t post_fpu_env[14];
179 __asm__ volatile("fstenv %0" : "=rm"(post_fpu_env));
180 EXPECT_EQ(0xffff, post_fpu_env[4])
181 << "FPU was left in an inconsistent state after call";
184 uint16_t pre_fpu_env_[14];
187 #define API_REGISTER_STATE_CHECK(statement) \
190 libvpx_test::RegisterStateCheckMMX reg_check; \
191 ASM_REGISTER_STATE_CHECK(statement); \
193 __asm__ volatile("" ::: "memory"); \
196 } // namespace libvpx_test
199 #endif // VPX_ARCH_X86 || VPX_ARCH_X86_64
201 #ifndef API_REGISTER_STATE_CHECK
202 #define API_REGISTER_STATE_CHECK ASM_REGISTER_STATE_CHECK
205 #endif // VPX_TEST_REGISTER_STATE_CHECK_H_