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 37namespace testing { 38namespace internal { 39 40inline 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 47namespace 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. 52class 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 97extern "C" { 98// Save the d8-d15 registers into store. 99void vp9_push_neon(int64_t *store); 100} 101 102namespace 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. 107class 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 143namespace libvpx_test { 144 145class 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 155namespace libvpx_test { 156 157// Checks the FPU tag word pre/post execution to ensure emms has been called. 158class 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_ 197