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 VPX_TEST_REGISTER_STATE_CHECK_H_ 12 #define VPX_TEST_REGISTER_STATE_CHECK_H_ 13 14 #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) && VPX_ARCH_X86_64 32 33 #undef NOMINMAX 34 #define NOMINMAX 35 #ifndef WIN32_LEAN_AND_MEAN 36 #define WIN32_LEAN_AND_MEAN 37 #endif 38 #include <intrin.h> 39 #include <windows.h> 40 #include <winnt.h> 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 libvpx_test { 47 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 50 // Windows x64. 51 class RegisterStateCheck { 52 public: RegisterStateCheck()53 RegisterStateCheck() { initialized_ = StoreRegisters(&pre_context_); } ~RegisterStateCheck()54 ~RegisterStateCheck() { Check(); } 55 56 private: StoreRegisters(CONTEXT * const context)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(); 63 return context_saved; 64 } 65 66 // Compares the register state. Returns true if the states match. Check()67 void Check() const { 68 ASSERT_TRUE(initialized_); 69 CONTEXT post_context; 70 ASSERT_TRUE(StoreRegisters(&post_context)); 71 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!"; 76 ++xmm_pre; 77 ++xmm_post; 78 } 79 } 80 81 bool initialized_; 82 CONTEXT pre_context_; 83 }; 84 85 #define ASM_REGISTER_STATE_CHECK(statement) \ 86 do { \ 87 { \ 88 libvpx_test::RegisterStateCheck reg_check; \ 89 statement; \ 90 } \ 91 _ReadWriteBarrier(); \ 92 } while (false) 93 94 } // namespace libvpx_test 95 96 #elif defined(CONFIG_SHARED) && defined(HAVE_NEON_ASM) && \ 97 defined(CONFIG_VP9) && !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() { vpx_push_neon(pre_store_); } ~RegisterStateCheck()112 ~RegisterStateCheck() { Check(); } 113 114 private: 115 // Compares the register state. Returns true if the states match. Check()116 void Check() const { 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"; 122 } 123 } 124 125 int64_t pre_store_[8]; 126 }; 127 128 #if defined(__GNUC__) 129 #define ASM_REGISTER_STATE_CHECK(statement) \ 130 do { \ 131 { \ 132 libvpx_test::RegisterStateCheck reg_check; \ 133 statement; \ 134 } \ 135 __asm__ volatile("" ::: "memory"); \ 136 } while (false) 137 #else 138 #define ASM_REGISTER_STATE_CHECK(statement) \ 139 do { \ 140 libvpx_test::RegisterStateCheck reg_check; \ 141 statement; \ 142 } while (false) 143 #endif 144 145 } // namespace libvpx_test 146 147 #else 148 149 namespace libvpx_test { 150 151 class RegisterStateCheck {}; 152 #define ASM_REGISTER_STATE_CHECK(statement) statement 153 154 } // namespace libvpx_test 155 156 #endif // _WIN64 && VPX_ARCH_X86_64 157 158 #if VPX_ARCH_X86 || VPX_ARCH_X86_64 159 #if defined(__GNUC__) 160 161 namespace libvpx_test { 162 163 // Checks the FPU tag word pre/post execution to ensure emms has been called. 164 class RegisterStateCheckMMX { 165 public: RegisterStateCheckMMX()166 RegisterStateCheckMMX() { 167 __asm__ volatile("fstenv %0" : "=rm"(pre_fpu_env_)); 168 } ~RegisterStateCheckMMX()169 ~RegisterStateCheckMMX() { Check(); } 170 171 private: 172 // Checks the FPU tag word pre/post execution, returning false if not cleared 173 // to 0xffff. Check()174 void Check() const { 175 EXPECT_EQ(0xffff, pre_fpu_env_[4]) 176 << "FPU was in an inconsistent state prior to call"; 177 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"; 182 } 183 184 uint16_t pre_fpu_env_[14]; 185 }; 186 187 #define API_REGISTER_STATE_CHECK(statement) \ 188 do { \ 189 { \ 190 libvpx_test::RegisterStateCheckMMX reg_check_mmx; \ 191 ASM_REGISTER_STATE_CHECK(statement); \ 192 } \ 193 __asm__ volatile("" ::: "memory"); \ 194 } while (false) 195 196 } // namespace libvpx_test 197 198 #endif // __GNUC__ 199 #endif // VPX_ARCH_X86 || VPX_ARCH_X86_64 200 201 #ifndef API_REGISTER_STATE_CHECK 202 #define API_REGISTER_STATE_CHECK ASM_REGISTER_STATE_CHECK 203 #endif 204 205 #endif // VPX_TEST_REGISTER_STATE_CHECK_H_ 206