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
17#if defined(_WIN64)
18
19#define _WIN32_LEAN_AND_MEAN
20#include <windows.h>
21#include <winnt.h>
22
23namespace testing {
24namespace internal {
25
26inline bool operator==(const M128A& lhs, const M128A& rhs) {
27  return (lhs.Low == rhs.Low && lhs.High == rhs.High);
28}
29
30}  // namespace internal
31}  // namespace testing
32
33namespace libvpx_test {
34
35// Compares the state of xmm[6-15] at construction with their state at
36// destruction. These registers should be preserved by the callee on
37// Windows x64.
38// Usage:
39// {
40//   RegisterStateCheck reg_check;
41//   FunctionToVerify();
42// }
43class RegisterStateCheck {
44 public:
45  RegisterStateCheck() { initialized_ = StoreRegisters(&pre_context_); }
46  ~RegisterStateCheck() { EXPECT_TRUE(Check()); }
47
48 private:
49  static bool StoreRegisters(CONTEXT* const context) {
50    const HANDLE this_thread = GetCurrentThread();
51    EXPECT_TRUE(this_thread != NULL);
52    context->ContextFlags = CONTEXT_FLOATING_POINT;
53    const bool context_saved = GetThreadContext(this_thread, context) == TRUE;
54    EXPECT_TRUE(context_saved) << "GetLastError: " << GetLastError();
55    return context_saved;
56  }
57
58  // Compares the register state. Returns true if the states match.
59  bool Check() const {
60    if (!initialized_) return false;
61    CONTEXT post_context;
62    if (!StoreRegisters(&post_context)) return false;
63
64    const M128A* xmm_pre = &pre_context_.Xmm6;
65    const M128A* xmm_post = &post_context.Xmm6;
66    for (int i = 6; i <= 15; ++i) {
67      EXPECT_EQ(*xmm_pre, *xmm_post) << "xmm" << i << " has been modified!";
68      ++xmm_pre;
69      ++xmm_post;
70    }
71    return !testing::Test::HasNonfatalFailure();
72  }
73
74  bool initialized_;
75  CONTEXT pre_context_;
76};
77
78#define REGISTER_STATE_CHECK(statement) do { \
79  libvpx_test::RegisterStateCheck reg_check; \
80  statement;                               \
81} while (false)
82
83}  // namespace libvpx_test
84
85#elif defined(CONFIG_SHARED) && defined(HAVE_NEON) \
86      && !CONFIG_SHARED && HAVE_NEON
87
88#include "vpx/vpx_integer.h"
89
90extern "C" {
91// Save the d8-d15 registers into store.
92void vp9_push_neon(int64_t *store);
93}
94
95namespace libvpx_test {
96
97// Compares the state of d8-d15 at construction with their state at
98// destruction. These registers should be preserved by the callee on
99// arm platform.
100// Usage:
101// {
102//   RegisterStateCheck reg_check;
103//   FunctionToVerify();
104// }
105class RegisterStateCheck {
106 public:
107  RegisterStateCheck() { initialized_ = StoreRegisters(pre_store_); }
108  ~RegisterStateCheck() { EXPECT_TRUE(Check()); }
109
110 private:
111  static bool StoreRegisters(int64_t store[8]) {
112    vp9_push_neon(store);
113    return true;
114  }
115
116  // Compares the register state. Returns true if the states match.
117  bool Check() const {
118    if (!initialized_) return false;
119    int64_t post_store[8];
120    vp9_push_neon(post_store);
121    for (int i = 0; i < 8; ++i) {
122      EXPECT_EQ(pre_store_[i], post_store[i]) << "d"
123          << i + 8 << " has been modified";
124    }
125    return !testing::Test::HasNonfatalFailure();
126  }
127
128  bool initialized_;
129  int64_t pre_store_[8];
130};
131
132#define REGISTER_STATE_CHECK(statement) do { \
133  libvpx_test::RegisterStateCheck reg_check; \
134  statement;                               \
135} while (false)
136
137}  // namespace libvpx_test
138
139#else
140
141namespace libvpx_test {
142
143class RegisterStateCheck {};
144#define REGISTER_STATE_CHECK(statement) statement
145
146}  // namespace libvpx_test
147
148#endif  // _WIN64
149
150#endif  // TEST_REGISTER_STATE_CHECK_H_
151