1d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org/* 2d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org * Copyright (c) 2012 The WebM project authors. All Rights Reserved. 3d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org * 4d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org * Use of this source code is governed by a BSD-style license 5d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org * that can be found in the LICENSE file in the root of the source 6d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org * tree. An additional intellectual property rights grant can be found 7d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org * in the file PATENTS. All contributing project authors may 8d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org * be found in the AUTHORS file in the root of the source tree. 9d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org */ 10d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org 11f9586bb54d74c97d07b09eb2512f8569c9c1c025fgalligan@chromium.org#ifndef TEST_REGISTER_STATE_CHECK_H_ 12f9586bb54d74c97d07b09eb2512f8569c9c1c025fgalligan@chromium.org#define TEST_REGISTER_STATE_CHECK_H_ 13d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org 1493a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org#include "third_party/googletest/src/include/gtest/gtest.h" 1593a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org#include "./vpx_config.h" 1695aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com#include "vpx/vpx_integer.h" 1795aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com 1895aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com// ASM_REGISTER_STATE_CHECK(asm_function) 1995aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com// Minimally validates the environment pre & post function execution. This 2095aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com// variant should be used with assembly functions which are not expected to 2195aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com// fully restore the system state. See platform implementations of 2295aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com// RegisterStateCheck for details. 2395aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com// 2495aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com// API_REGISTER_STATE_CHECK(api_function) 2595aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com// Performs all the checks done by ASM_REGISTER_STATE_CHECK() and any 2695aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com// additional checks to ensure the environment is in a consistent state pre & 2795aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com// post function execution. This variant should be used with API functions. 2895aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com// See platform implementations of RegisterStateCheckXXX for details. 2995aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com// 3093a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org 3193a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org#if defined(_WIN64) 32d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org 33d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org#define _WIN32_LEAN_AND_MEAN 34d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org#include <windows.h> 35d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org#include <winnt.h> 36d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org 37d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.orgnamespace testing { 38d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.orgnamespace internal { 39d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org 40d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.orginline bool operator==(const M128A& lhs, const M128A& rhs) { 41d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org return (lhs.Low == rhs.Low && lhs.High == rhs.High); 42d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org} 43d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org 44d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org} // namespace internal 45d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org} // namespace testing 46d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org 47d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.orgnamespace libvpx_test { 48d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org 49d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org// Compares the state of xmm[6-15] at construction with their state at 50d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org// destruction. These registers should be preserved by the callee on 51d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org// Windows x64. 52d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.orgclass RegisterStateCheck { 53d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org public: 54d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org RegisterStateCheck() { initialized_ = StoreRegisters(&pre_context_); } 55d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org ~RegisterStateCheck() { EXPECT_TRUE(Check()); } 56d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org 57d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org private: 58d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org static bool StoreRegisters(CONTEXT* const context) { 59d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org const HANDLE this_thread = GetCurrentThread(); 60d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org EXPECT_TRUE(this_thread != NULL); 61d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org context->ContextFlags = CONTEXT_FLOATING_POINT; 62d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org const bool context_saved = GetThreadContext(this_thread, context) == TRUE; 63d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org EXPECT_TRUE(context_saved) << "GetLastError: " << GetLastError(); 64d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org return context_saved; 65d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org } 66d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org 67d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org // Compares the register state. Returns true if the states match. 68d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org bool Check() const { 69d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org if (!initialized_) return false; 70d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org CONTEXT post_context; 71d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org if (!StoreRegisters(&post_context)) return false; 72d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org 73d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org const M128A* xmm_pre = &pre_context_.Xmm6; 74d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org const M128A* xmm_post = &post_context.Xmm6; 75d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org for (int i = 6; i <= 15; ++i) { 76d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org EXPECT_EQ(*xmm_pre, *xmm_post) << "xmm" << i << " has been modified!"; 77d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org ++xmm_pre; 78d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org ++xmm_post; 79d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org } 80d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org return !testing::Test::HasNonfatalFailure(); 81d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org } 82d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org 83d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org bool initialized_; 84d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org CONTEXT pre_context_; 85d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org}; 86d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org 8795aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com#define ASM_REGISTER_STATE_CHECK(statement) do { \ 8895aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com libvpx_test::RegisterStateCheck reg_check; \ 8995aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com statement; \ 90d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org} while (false) 91d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org 92d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org} // namespace libvpx_test 93d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org 947765c078fa920ba6c949c15f16b6cc979d8bb95bjohannkoenig@chromium.org#elif defined(CONFIG_SHARED) && defined(HAVE_NEON_ASM) && defined(CONFIG_VP9) \ 957765c078fa920ba6c949c15f16b6cc979d8bb95bjohannkoenig@chromium.org && !CONFIG_SHARED && HAVE_NEON_ASM && CONFIG_VP9 9693a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org 9793a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.orgextern "C" { 9893a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org// Save the d8-d15 registers into store. 9993a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.orgvoid vp9_push_neon(int64_t *store); 10093a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org} 10193a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org 10293a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.orgnamespace libvpx_test { 10393a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org 10493a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org// Compares the state of d8-d15 at construction with their state at 10593a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org// destruction. These registers should be preserved by the callee on 10693a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org// arm platform. 10793a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.orgclass RegisterStateCheck { 10893a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org public: 10993a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org RegisterStateCheck() { initialized_ = StoreRegisters(pre_store_); } 11093a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org ~RegisterStateCheck() { EXPECT_TRUE(Check()); } 11193a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org 11293a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org private: 11393a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org static bool StoreRegisters(int64_t store[8]) { 11493a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org vp9_push_neon(store); 11593a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org return true; 11693a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org } 11793a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org 11893a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org // Compares the register state. Returns true if the states match. 11993a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org bool Check() const { 12093a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org if (!initialized_) return false; 12193a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org int64_t post_store[8]; 12293a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org vp9_push_neon(post_store); 12393a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org for (int i = 0; i < 8; ++i) { 12493a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org EXPECT_EQ(pre_store_[i], post_store[i]) << "d" 12593a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org << i + 8 << " has been modified"; 12693a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org } 12793a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org return !testing::Test::HasNonfatalFailure(); 12893a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org } 12993a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org 13093a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org bool initialized_; 13193a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org int64_t pre_store_[8]; 13293a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org}; 13393a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org 13495aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com#define ASM_REGISTER_STATE_CHECK(statement) do { \ 13595aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com libvpx_test::RegisterStateCheck reg_check; \ 13695aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com statement; \ 13793a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org} while (false) 13893a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org 13993a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org} // namespace libvpx_test 14093a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org 14193a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org#else 142d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org 143d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.orgnamespace libvpx_test { 144d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org 145d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.orgclass RegisterStateCheck {}; 14695aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com#define ASM_REGISTER_STATE_CHECK(statement) statement 147d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org 148d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org} // namespace libvpx_test 149d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org 150d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org#endif // _WIN64 151d348b8d765c019ee7250075d663a83db00c65c08tomfinegan@chromium.org 15295aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com#if ARCH_X86 || ARCH_X86_64 15395aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com#if defined(__GNUC__) 15495aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com 15595aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.comnamespace libvpx_test { 15695aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com 15795aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com// Checks the FPU tag word pre/post execution to ensure emms has been called. 15895aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.comclass RegisterStateCheckMMX { 15995aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com public: 16095aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com RegisterStateCheckMMX() { 16195aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com __asm__ volatile("fstenv %0" : "=rm"(pre_fpu_env_)); 16295aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com } 16395aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com ~RegisterStateCheckMMX() { EXPECT_TRUE(Check()); } 16495aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com 16595aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com private: 16695aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com // Checks the FPU tag word pre/post execution, returning false if not cleared 16795aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com // to 0xffff. 16895aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com bool Check() const { 16995aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com EXPECT_EQ(0xffff, pre_fpu_env_[4]) 17095aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com << "FPU was in an inconsistent state prior to call"; 17195aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com 17295aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com uint16_t post_fpu_env[14]; 17395aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com __asm__ volatile("fstenv %0" : "=rm"(post_fpu_env)); 17495aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com EXPECT_EQ(0xffff, post_fpu_env[4]) 17595aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com << "FPU was left in an inconsistent state after call"; 17695aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com return !testing::Test::HasNonfatalFailure(); 17795aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com } 17895aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com 17995aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com uint16_t pre_fpu_env_[14]; 18095aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com}; 18195aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com 18295aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com#define API_REGISTER_STATE_CHECK(statement) do { \ 18395aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com libvpx_test::RegisterStateCheckMMX reg_check; \ 18495aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com ASM_REGISTER_STATE_CHECK(statement); \ 18595aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com} while (false) 18695aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com 18795aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com} // namespace libvpx_test 18895aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com 18995aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com#endif // __GNUC__ 19095aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com#endif // ARCH_X86 || ARCH_X86_64 19195aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com 19295aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com#ifndef API_REGISTER_STATE_CHECK 19395aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com#define API_REGISTER_STATE_CHECK ASM_REGISTER_STATE_CHECK 19495aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com#endif 19595aa45d73048f952dcaad0037429cc6751b34f2fjohannkoenig@google.com 196f9586bb54d74c97d07b09eb2512f8569c9c1c025fgalligan@chromium.org#endif // TEST_REGISTER_STATE_CHECK_H_ 197