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