xref: /aosp_15_r20/external/libaom/test/register_state_check.h (revision 77c1e3ccc04c968bd2bc212e87364f250e820521)
1 /*
2  * Copyright (c) 2016, Alliance for Open Media. All rights reserved.
3  *
4  * This source code is subject to the terms of the BSD 2 Clause License and
5  * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6  * was not distributed with this source code in the LICENSE file, you can
7  * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8  * Media Patent License 1.0 was not distributed with this source code in the
9  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10  */
11 
12 #ifndef AOM_TEST_REGISTER_STATE_CHECK_H_
13 #define AOM_TEST_REGISTER_STATE_CHECK_H_
14 
15 #include "gtest/gtest.h"
16 
17 #include "config/aom_config.h"
18 
19 #include "aom/aom_integer.h"
20 
21 // API_REGISTER_STATE_CHECK(function)
22 //   Validates the environment pre & post function execution to ensure the
23 //   environment is in a consistent state. This should be used with API
24 //   function sand assembly functions which are not expected to fully restore
25 //   the system state.
26 //   See platform implementations of RegisterStateCheck and
27 //   RegisterStateCheckMMX for details.
28 
29 #if defined(_WIN64) && AOM_ARCH_X86_64
30 
31 #undef NOMINMAX
32 #define NOMINMAX
33 #undef WIN32_LEAN_AND_MEAN
34 #define WIN32_LEAN_AND_MEAN
35 #include <windows.h>
36 #include <winnt.h>
37 
38 inline bool operator==(const M128A &lhs, const M128A &rhs) {
39   return (lhs.Low == rhs.Low && lhs.High == rhs.High);
40 }
41 
42 namespace libaom_test {
43 
44 // Compares the state of xmm[6-15] at construction with their state at
45 // destruction. These registers should be preserved by the callee on
46 // Windows x64.
47 class RegisterStateCheck {
48  public:
RegisterStateCheck()49   RegisterStateCheck() { initialized_ = StoreRegisters(&pre_context_); }
~RegisterStateCheck()50   ~RegisterStateCheck() { Check(); }
51 
52  private:
StoreRegisters(CONTEXT * const context)53   static bool StoreRegisters(CONTEXT *const context) {
54     const HANDLE this_thread = GetCurrentThread();
55     EXPECT_NE(this_thread, nullptr);
56     context->ContextFlags = CONTEXT_FLOATING_POINT;
57     const bool context_saved = GetThreadContext(this_thread, context) == TRUE;
58     EXPECT_TRUE(context_saved) << "GetLastError: " << GetLastError();
59     return context_saved;
60   }
61 
62   // Compares the register state. Returns true if the states match.
Check()63   void Check() const {
64     ASSERT_TRUE(initialized_);
65     CONTEXT post_context;
66     ASSERT_TRUE(StoreRegisters(&post_context));
67 
68     const M128A *xmm_pre = &pre_context_.Xmm6;
69     const M128A *xmm_post = &post_context.Xmm6;
70     for (int i = 6; i <= 15; ++i) {
71       EXPECT_EQ(*xmm_pre, *xmm_post) << "xmm" << i << " has been modified!";
72       ++xmm_pre;
73       ++xmm_post;
74     }
75   }
76 
77   bool initialized_;
78   CONTEXT pre_context_;
79 };
80 }  // namespace libaom_test
81 
82 #else
83 
84 namespace libaom_test {
85 
86 class RegisterStateCheck {};
87 }  // namespace libaom_test
88 
89 #endif  // _WIN64 && AOM_ARCH_X86_64
90 
91 #if (AOM_ARCH_X86 || AOM_ARCH_X86_64) && defined(__GNUC__)
92 namespace libaom_test {
93 
94 // Checks the FPU tag word pre/post execution to ensure emms has been called.
95 class RegisterStateCheckMMX {
96  public:
RegisterStateCheckMMX()97   RegisterStateCheckMMX() {
98     __asm__ volatile("fstenv %0" : "=rm"(pre_fpu_env_));
99   }
~RegisterStateCheckMMX()100   ~RegisterStateCheckMMX() { Check(); }
101 
102  private:
103   // Checks the FPU tag word pre/post execution, returning false if not cleared
104   // to 0xffff.
Check()105   void Check() const {
106     EXPECT_EQ(0xffff, pre_fpu_env_[4])
107         << "FPU was in an inconsistent state prior to call";
108 
109     uint16_t post_fpu_env[14];
110     __asm__ volatile("fstenv %0" : "=rm"(post_fpu_env));
111     EXPECT_EQ(0xffff, post_fpu_env[4])
112         << "FPU was left in an inconsistent state after call";
113   }
114 
115   uint16_t pre_fpu_env_[14];
116 };
117 }  // namespace libaom_test
118 
119 #else
120 namespace libaom_test {
121 
122 class RegisterStateCheckMMX {};
123 }  // namespace libaom_test
124 
125 #endif  // (AOM_ARCH_X86 || AOM_ARCH_X86_64) && defined(__GNUC__)
126 
127 #define API_REGISTER_STATE_CHECK(statement)           \
128   do {                                                \
129     libaom_test::RegisterStateCheck reg_check;        \
130     libaom_test::RegisterStateCheckMMX reg_check_mmx; \
131     statement;                                        \
132     (void)reg_check_mmx;                              \
133     (void)reg_check;                                  \
134   } while (false)
135 
136 #endif  // AOM_TEST_REGISTER_STATE_CHECK_H_
137