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 #undef NOMINMAX 34 #define NOMINMAX 35 #ifndef WIN32_LEAN_AND_MEAN 36 #define WIN32_LEAN_AND_MEAN 37 #endif 38 #include <windows.h> 39 #include <winnt.h> 40 41 inline bool operator==(const M128A &lhs, const M128A &rhs) { 42 return (lhs.Low == rhs.Low && lhs.High == rhs.High); 43 } 44 45 namespace libvpx_test { 46 47 // Compares the state of xmm[6-15] at construction with their state at 48 // destruction. These registers should be preserved by the callee on 49 // Windows x64. 50 class RegisterStateCheck { 51 public: RegisterStateCheck()52 RegisterStateCheck() { initialized_ = StoreRegisters(&pre_context_); } ~RegisterStateCheck()53 ~RegisterStateCheck() { Check(); } 54 55 private: StoreRegisters(CONTEXT * const context)56 static bool StoreRegisters(CONTEXT *const context) { 57 const HANDLE this_thread = GetCurrentThread(); 58 EXPECT_TRUE(this_thread != NULL); 59 context->ContextFlags = CONTEXT_FLOATING_POINT; 60 const bool context_saved = GetThreadContext(this_thread, context) == TRUE; 61 EXPECT_TRUE(context_saved) << "GetLastError: " << GetLastError(); 62 return context_saved; 63 } 64 65 // Compares the register state. Returns true if the states match. Check()66 void Check() const { 67 ASSERT_TRUE(initialized_); 68 CONTEXT post_context; 69 ASSERT_TRUE(StoreRegisters(&post_context)); 70 71 const M128A *xmm_pre = &pre_context_.Xmm6; 72 const M128A *xmm_post = &post_context.Xmm6; 73 for (int i = 6; i <= 15; ++i) { 74 EXPECT_EQ(*xmm_pre, *xmm_post) << "xmm" << i << " has been modified!"; 75 ++xmm_pre; 76 ++xmm_post; 77 } 78 } 79 80 bool initialized_; 81 CONTEXT pre_context_; 82 }; 83 84 #define ASM_REGISTER_STATE_CHECK(statement) \ 85 do { \ 86 libvpx_test::RegisterStateCheck reg_check; \ 87 statement; \ 88 } while (false) 89 90 } // namespace libvpx_test 91 92 #elif defined(CONFIG_SHARED) && defined(HAVE_NEON_ASM) && \ 93 defined(CONFIG_VP9) && !CONFIG_SHARED && HAVE_NEON_ASM && CONFIG_VP9 94 95 extern "C" { 96 // Save the d8-d15 registers into store. 97 void vpx_push_neon(int64_t *store); 98 } 99 100 namespace libvpx_test { 101 102 // Compares the state of d8-d15 at construction with their state at 103 // destruction. These registers should be preserved by the callee on 104 // arm platform. 105 class RegisterStateCheck { 106 public: RegisterStateCheck()107 RegisterStateCheck() { vpx_push_neon(pre_store_); } ~RegisterStateCheck()108 ~RegisterStateCheck() { Check(); } 109 110 private: 111 // Compares the register state. Returns true if the states match. Check()112 void Check() const { 113 int64_t post_store[8]; 114 vpx_push_neon(post_store); 115 for (int i = 0; i < 8; ++i) { 116 EXPECT_EQ(pre_store_[i], post_store[i]) << "d" << i + 8 117 << " has been modified"; 118 } 119 } 120 121 int64_t pre_store_[8]; 122 }; 123 124 #define ASM_REGISTER_STATE_CHECK(statement) \ 125 do { \ 126 libvpx_test::RegisterStateCheck reg_check; \ 127 statement; \ 128 } while (false) 129 130 } // namespace libvpx_test 131 132 #else 133 134 namespace libvpx_test { 135 136 class RegisterStateCheck {}; 137 #define ASM_REGISTER_STATE_CHECK(statement) statement 138 139 } // namespace libvpx_test 140 141 #endif // _WIN64 142 143 #if ARCH_X86 || ARCH_X86_64 144 #if defined(__GNUC__) 145 146 namespace libvpx_test { 147 148 // Checks the FPU tag word pre/post execution to ensure emms has been called. 149 class RegisterStateCheckMMX { 150 public: RegisterStateCheckMMX()151 RegisterStateCheckMMX() { 152 __asm__ volatile("fstenv %0" : "=rm"(pre_fpu_env_)); 153 } ~RegisterStateCheckMMX()154 ~RegisterStateCheckMMX() { Check(); } 155 156 private: 157 // Checks the FPU tag word pre/post execution, returning false if not cleared 158 // to 0xffff. Check()159 void Check() const { 160 EXPECT_EQ(0xffff, pre_fpu_env_[4]) 161 << "FPU was in an inconsistent state prior to call"; 162 163 uint16_t post_fpu_env[14]; 164 __asm__ volatile("fstenv %0" : "=rm"(post_fpu_env)); 165 EXPECT_EQ(0xffff, post_fpu_env[4]) 166 << "FPU was left in an inconsistent state after call"; 167 } 168 169 uint16_t pre_fpu_env_[14]; 170 }; 171 172 #define API_REGISTER_STATE_CHECK(statement) \ 173 do { \ 174 libvpx_test::RegisterStateCheckMMX reg_check; \ 175 ASM_REGISTER_STATE_CHECK(statement); \ 176 } while (false) 177 178 } // namespace libvpx_test 179 180 #endif // __GNUC__ 181 #endif // ARCH_X86 || ARCH_X86_64 182 183 #ifndef API_REGISTER_STATE_CHECK 184 #define API_REGISTER_STATE_CHECK ASM_REGISTER_STATE_CHECK 185 #endif 186 187 #endif // TEST_REGISTER_STATE_CHECK_H_ 188