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