xref: /aosp_15_r20/external/libvpx/test/register_state_check.h (revision fb1b10ab9aebc7c7068eedab379b749d7e3900be)
1*fb1b10abSAndroid Build Coastguard Worker /*
2*fb1b10abSAndroid Build Coastguard Worker  *  Copyright (c) 2012 The WebM project authors. All Rights Reserved.
3*fb1b10abSAndroid Build Coastguard Worker  *
4*fb1b10abSAndroid Build Coastguard Worker  *  Use of this source code is governed by a BSD-style license
5*fb1b10abSAndroid Build Coastguard Worker  *  that can be found in the LICENSE file in the root of the source
6*fb1b10abSAndroid Build Coastguard Worker  *  tree. An additional intellectual property rights grant can be found
7*fb1b10abSAndroid Build Coastguard Worker  *  in the file PATENTS.  All contributing project authors may
8*fb1b10abSAndroid Build Coastguard Worker  *  be found in the AUTHORS file in the root of the source tree.
9*fb1b10abSAndroid Build Coastguard Worker  */
10*fb1b10abSAndroid Build Coastguard Worker 
11*fb1b10abSAndroid Build Coastguard Worker #ifndef VPX_TEST_REGISTER_STATE_CHECK_H_
12*fb1b10abSAndroid Build Coastguard Worker #define VPX_TEST_REGISTER_STATE_CHECK_H_
13*fb1b10abSAndroid Build Coastguard Worker 
14*fb1b10abSAndroid Build Coastguard Worker #include "gtest/gtest.h"
15*fb1b10abSAndroid Build Coastguard Worker #include "./vpx_config.h"
16*fb1b10abSAndroid Build Coastguard Worker #include "vpx/vpx_integer.h"
17*fb1b10abSAndroid Build Coastguard Worker 
18*fb1b10abSAndroid Build Coastguard Worker // ASM_REGISTER_STATE_CHECK(asm_function)
19*fb1b10abSAndroid Build Coastguard Worker //   Minimally validates the environment pre & post function execution. This
20*fb1b10abSAndroid Build Coastguard Worker //   variant should be used with assembly functions which are not expected to
21*fb1b10abSAndroid Build Coastguard Worker //   fully restore the system state. See platform implementations of
22*fb1b10abSAndroid Build Coastguard Worker //   RegisterStateCheck for details.
23*fb1b10abSAndroid Build Coastguard Worker //
24*fb1b10abSAndroid Build Coastguard Worker // API_REGISTER_STATE_CHECK(api_function)
25*fb1b10abSAndroid Build Coastguard Worker //   Performs all the checks done by ASM_REGISTER_STATE_CHECK() and any
26*fb1b10abSAndroid Build Coastguard Worker //   additional checks to ensure the environment is in a consistent state pre &
27*fb1b10abSAndroid Build Coastguard Worker //   post function execution. This variant should be used with API functions.
28*fb1b10abSAndroid Build Coastguard Worker //   See platform implementations of RegisterStateCheckXXX for details.
29*fb1b10abSAndroid Build Coastguard Worker //
30*fb1b10abSAndroid Build Coastguard Worker 
31*fb1b10abSAndroid Build Coastguard Worker #if defined(_WIN64) && VPX_ARCH_X86_64
32*fb1b10abSAndroid Build Coastguard Worker 
33*fb1b10abSAndroid Build Coastguard Worker #undef NOMINMAX
34*fb1b10abSAndroid Build Coastguard Worker #define NOMINMAX
35*fb1b10abSAndroid Build Coastguard Worker #ifndef WIN32_LEAN_AND_MEAN
36*fb1b10abSAndroid Build Coastguard Worker #define WIN32_LEAN_AND_MEAN
37*fb1b10abSAndroid Build Coastguard Worker #endif
38*fb1b10abSAndroid Build Coastguard Worker #include <intrin.h>
39*fb1b10abSAndroid Build Coastguard Worker #include <windows.h>
40*fb1b10abSAndroid Build Coastguard Worker #include <winnt.h>
41*fb1b10abSAndroid Build Coastguard Worker 
42*fb1b10abSAndroid Build Coastguard Worker inline bool operator==(const M128A &lhs, const M128A &rhs) {
43*fb1b10abSAndroid Build Coastguard Worker   return (lhs.Low == rhs.Low && lhs.High == rhs.High);
44*fb1b10abSAndroid Build Coastguard Worker }
45*fb1b10abSAndroid Build Coastguard Worker 
46*fb1b10abSAndroid Build Coastguard Worker namespace libvpx_test {
47*fb1b10abSAndroid Build Coastguard Worker 
48*fb1b10abSAndroid Build Coastguard Worker // Compares the state of xmm[6-15] at construction with their state at
49*fb1b10abSAndroid Build Coastguard Worker // destruction. These registers should be preserved by the callee on
50*fb1b10abSAndroid Build Coastguard Worker // Windows x64.
51*fb1b10abSAndroid Build Coastguard Worker class RegisterStateCheck {
52*fb1b10abSAndroid Build Coastguard Worker  public:
RegisterStateCheck()53*fb1b10abSAndroid Build Coastguard Worker   RegisterStateCheck() { initialized_ = StoreRegisters(&pre_context_); }
~RegisterStateCheck()54*fb1b10abSAndroid Build Coastguard Worker   ~RegisterStateCheck() { Check(); }
55*fb1b10abSAndroid Build Coastguard Worker 
56*fb1b10abSAndroid Build Coastguard Worker  private:
StoreRegisters(CONTEXT * const context)57*fb1b10abSAndroid Build Coastguard Worker   static bool StoreRegisters(CONTEXT *const context) {
58*fb1b10abSAndroid Build Coastguard Worker     const HANDLE this_thread = GetCurrentThread();
59*fb1b10abSAndroid Build Coastguard Worker     EXPECT_NE(this_thread, nullptr);
60*fb1b10abSAndroid Build Coastguard Worker     context->ContextFlags = CONTEXT_FLOATING_POINT;
61*fb1b10abSAndroid Build Coastguard Worker     const bool context_saved = GetThreadContext(this_thread, context) == TRUE;
62*fb1b10abSAndroid Build Coastguard Worker     EXPECT_TRUE(context_saved) << "GetLastError: " << GetLastError();
63*fb1b10abSAndroid Build Coastguard Worker     return context_saved;
64*fb1b10abSAndroid Build Coastguard Worker   }
65*fb1b10abSAndroid Build Coastguard Worker 
66*fb1b10abSAndroid Build Coastguard Worker   // Compares the register state. Returns true if the states match.
Check()67*fb1b10abSAndroid Build Coastguard Worker   void Check() const {
68*fb1b10abSAndroid Build Coastguard Worker     ASSERT_TRUE(initialized_);
69*fb1b10abSAndroid Build Coastguard Worker     CONTEXT post_context;
70*fb1b10abSAndroid Build Coastguard Worker     ASSERT_TRUE(StoreRegisters(&post_context));
71*fb1b10abSAndroid Build Coastguard Worker 
72*fb1b10abSAndroid Build Coastguard Worker     const M128A *xmm_pre = &pre_context_.Xmm6;
73*fb1b10abSAndroid Build Coastguard Worker     const M128A *xmm_post = &post_context.Xmm6;
74*fb1b10abSAndroid Build Coastguard Worker     for (int i = 6; i <= 15; ++i) {
75*fb1b10abSAndroid Build Coastguard Worker       EXPECT_EQ(*xmm_pre, *xmm_post) << "xmm" << i << " has been modified!";
76*fb1b10abSAndroid Build Coastguard Worker       ++xmm_pre;
77*fb1b10abSAndroid Build Coastguard Worker       ++xmm_post;
78*fb1b10abSAndroid Build Coastguard Worker     }
79*fb1b10abSAndroid Build Coastguard Worker   }
80*fb1b10abSAndroid Build Coastguard Worker 
81*fb1b10abSAndroid Build Coastguard Worker   bool initialized_;
82*fb1b10abSAndroid Build Coastguard Worker   CONTEXT pre_context_;
83*fb1b10abSAndroid Build Coastguard Worker };
84*fb1b10abSAndroid Build Coastguard Worker 
85*fb1b10abSAndroid Build Coastguard Worker #define ASM_REGISTER_STATE_CHECK(statement)      \
86*fb1b10abSAndroid Build Coastguard Worker   do {                                           \
87*fb1b10abSAndroid Build Coastguard Worker     {                                            \
88*fb1b10abSAndroid Build Coastguard Worker       libvpx_test::RegisterStateCheck reg_check; \
89*fb1b10abSAndroid Build Coastguard Worker       statement;                                 \
90*fb1b10abSAndroid Build Coastguard Worker     }                                            \
91*fb1b10abSAndroid Build Coastguard Worker     _ReadWriteBarrier();                         \
92*fb1b10abSAndroid Build Coastguard Worker   } while (false)
93*fb1b10abSAndroid Build Coastguard Worker 
94*fb1b10abSAndroid Build Coastguard Worker }  // namespace libvpx_test
95*fb1b10abSAndroid Build Coastguard Worker 
96*fb1b10abSAndroid Build Coastguard Worker #elif defined(CONFIG_SHARED) && defined(HAVE_NEON_ASM) && \
97*fb1b10abSAndroid Build Coastguard Worker     defined(CONFIG_VP9) && !CONFIG_SHARED && HAVE_NEON_ASM && CONFIG_VP9
98*fb1b10abSAndroid Build Coastguard Worker 
99*fb1b10abSAndroid Build Coastguard Worker extern "C" {
100*fb1b10abSAndroid Build Coastguard Worker // Save the d8-d15 registers into store.
101*fb1b10abSAndroid Build Coastguard Worker void vpx_push_neon(int64_t *store);
102*fb1b10abSAndroid Build Coastguard Worker }
103*fb1b10abSAndroid Build Coastguard Worker 
104*fb1b10abSAndroid Build Coastguard Worker namespace libvpx_test {
105*fb1b10abSAndroid Build Coastguard Worker 
106*fb1b10abSAndroid Build Coastguard Worker // Compares the state of d8-d15 at construction with their state at
107*fb1b10abSAndroid Build Coastguard Worker // destruction. These registers should be preserved by the callee on
108*fb1b10abSAndroid Build Coastguard Worker // arm platform.
109*fb1b10abSAndroid Build Coastguard Worker class RegisterStateCheck {
110*fb1b10abSAndroid Build Coastguard Worker  public:
RegisterStateCheck()111*fb1b10abSAndroid Build Coastguard Worker   RegisterStateCheck() { vpx_push_neon(pre_store_); }
~RegisterStateCheck()112*fb1b10abSAndroid Build Coastguard Worker   ~RegisterStateCheck() { Check(); }
113*fb1b10abSAndroid Build Coastguard Worker 
114*fb1b10abSAndroid Build Coastguard Worker  private:
115*fb1b10abSAndroid Build Coastguard Worker   // Compares the register state. Returns true if the states match.
Check()116*fb1b10abSAndroid Build Coastguard Worker   void Check() const {
117*fb1b10abSAndroid Build Coastguard Worker     int64_t post_store[8];
118*fb1b10abSAndroid Build Coastguard Worker     vpx_push_neon(post_store);
119*fb1b10abSAndroid Build Coastguard Worker     for (int i = 0; i < 8; ++i) {
120*fb1b10abSAndroid Build Coastguard Worker       EXPECT_EQ(pre_store_[i], post_store[i])
121*fb1b10abSAndroid Build Coastguard Worker           << "d" << i + 8 << " has been modified";
122*fb1b10abSAndroid Build Coastguard Worker     }
123*fb1b10abSAndroid Build Coastguard Worker   }
124*fb1b10abSAndroid Build Coastguard Worker 
125*fb1b10abSAndroid Build Coastguard Worker   int64_t pre_store_[8];
126*fb1b10abSAndroid Build Coastguard Worker };
127*fb1b10abSAndroid Build Coastguard Worker 
128*fb1b10abSAndroid Build Coastguard Worker #if defined(__GNUC__)
129*fb1b10abSAndroid Build Coastguard Worker #define ASM_REGISTER_STATE_CHECK(statement)      \
130*fb1b10abSAndroid Build Coastguard Worker   do {                                           \
131*fb1b10abSAndroid Build Coastguard Worker     {                                            \
132*fb1b10abSAndroid Build Coastguard Worker       libvpx_test::RegisterStateCheck reg_check; \
133*fb1b10abSAndroid Build Coastguard Worker       statement;                                 \
134*fb1b10abSAndroid Build Coastguard Worker     }                                            \
135*fb1b10abSAndroid Build Coastguard Worker     __asm__ volatile("" ::: "memory");           \
136*fb1b10abSAndroid Build Coastguard Worker   } while (false)
137*fb1b10abSAndroid Build Coastguard Worker #else
138*fb1b10abSAndroid Build Coastguard Worker #define ASM_REGISTER_STATE_CHECK(statement)    \
139*fb1b10abSAndroid Build Coastguard Worker   do {                                         \
140*fb1b10abSAndroid Build Coastguard Worker     libvpx_test::RegisterStateCheck reg_check; \
141*fb1b10abSAndroid Build Coastguard Worker     statement;                                 \
142*fb1b10abSAndroid Build Coastguard Worker   } while (false)
143*fb1b10abSAndroid Build Coastguard Worker #endif
144*fb1b10abSAndroid Build Coastguard Worker 
145*fb1b10abSAndroid Build Coastguard Worker }  // namespace libvpx_test
146*fb1b10abSAndroid Build Coastguard Worker 
147*fb1b10abSAndroid Build Coastguard Worker #else
148*fb1b10abSAndroid Build Coastguard Worker 
149*fb1b10abSAndroid Build Coastguard Worker namespace libvpx_test {
150*fb1b10abSAndroid Build Coastguard Worker 
151*fb1b10abSAndroid Build Coastguard Worker class RegisterStateCheck {};
152*fb1b10abSAndroid Build Coastguard Worker #define ASM_REGISTER_STATE_CHECK(statement) statement
153*fb1b10abSAndroid Build Coastguard Worker 
154*fb1b10abSAndroid Build Coastguard Worker }  // namespace libvpx_test
155*fb1b10abSAndroid Build Coastguard Worker 
156*fb1b10abSAndroid Build Coastguard Worker #endif  // _WIN64 && VPX_ARCH_X86_64
157*fb1b10abSAndroid Build Coastguard Worker 
158*fb1b10abSAndroid Build Coastguard Worker #if VPX_ARCH_X86 || VPX_ARCH_X86_64
159*fb1b10abSAndroid Build Coastguard Worker #if defined(__GNUC__)
160*fb1b10abSAndroid Build Coastguard Worker 
161*fb1b10abSAndroid Build Coastguard Worker namespace libvpx_test {
162*fb1b10abSAndroid Build Coastguard Worker 
163*fb1b10abSAndroid Build Coastguard Worker // Checks the FPU tag word pre/post execution to ensure emms has been called.
164*fb1b10abSAndroid Build Coastguard Worker class RegisterStateCheckMMX {
165*fb1b10abSAndroid Build Coastguard Worker  public:
RegisterStateCheckMMX()166*fb1b10abSAndroid Build Coastguard Worker   RegisterStateCheckMMX() {
167*fb1b10abSAndroid Build Coastguard Worker     __asm__ volatile("fstenv %0" : "=rm"(pre_fpu_env_));
168*fb1b10abSAndroid Build Coastguard Worker   }
~RegisterStateCheckMMX()169*fb1b10abSAndroid Build Coastguard Worker   ~RegisterStateCheckMMX() { Check(); }
170*fb1b10abSAndroid Build Coastguard Worker 
171*fb1b10abSAndroid Build Coastguard Worker  private:
172*fb1b10abSAndroid Build Coastguard Worker   // Checks the FPU tag word pre/post execution, returning false if not cleared
173*fb1b10abSAndroid Build Coastguard Worker   // to 0xffff.
Check()174*fb1b10abSAndroid Build Coastguard Worker   void Check() const {
175*fb1b10abSAndroid Build Coastguard Worker     EXPECT_EQ(0xffff, pre_fpu_env_[4])
176*fb1b10abSAndroid Build Coastguard Worker         << "FPU was in an inconsistent state prior to call";
177*fb1b10abSAndroid Build Coastguard Worker 
178*fb1b10abSAndroid Build Coastguard Worker     uint16_t post_fpu_env[14];
179*fb1b10abSAndroid Build Coastguard Worker     __asm__ volatile("fstenv %0" : "=rm"(post_fpu_env));
180*fb1b10abSAndroid Build Coastguard Worker     EXPECT_EQ(0xffff, post_fpu_env[4])
181*fb1b10abSAndroid Build Coastguard Worker         << "FPU was left in an inconsistent state after call";
182*fb1b10abSAndroid Build Coastguard Worker   }
183*fb1b10abSAndroid Build Coastguard Worker 
184*fb1b10abSAndroid Build Coastguard Worker   uint16_t pre_fpu_env_[14];
185*fb1b10abSAndroid Build Coastguard Worker };
186*fb1b10abSAndroid Build Coastguard Worker 
187*fb1b10abSAndroid Build Coastguard Worker #define API_REGISTER_STATE_CHECK(statement)             \
188*fb1b10abSAndroid Build Coastguard Worker   do {                                                  \
189*fb1b10abSAndroid Build Coastguard Worker     {                                                   \
190*fb1b10abSAndroid Build Coastguard Worker       libvpx_test::RegisterStateCheckMMX reg_check_mmx; \
191*fb1b10abSAndroid Build Coastguard Worker       ASM_REGISTER_STATE_CHECK(statement);              \
192*fb1b10abSAndroid Build Coastguard Worker     }                                                   \
193*fb1b10abSAndroid Build Coastguard Worker     __asm__ volatile("" ::: "memory");                  \
194*fb1b10abSAndroid Build Coastguard Worker   } while (false)
195*fb1b10abSAndroid Build Coastguard Worker 
196*fb1b10abSAndroid Build Coastguard Worker }  // namespace libvpx_test
197*fb1b10abSAndroid Build Coastguard Worker 
198*fb1b10abSAndroid Build Coastguard Worker #endif  // __GNUC__
199*fb1b10abSAndroid Build Coastguard Worker #endif  // VPX_ARCH_X86 || VPX_ARCH_X86_64
200*fb1b10abSAndroid Build Coastguard Worker 
201*fb1b10abSAndroid Build Coastguard Worker #ifndef API_REGISTER_STATE_CHECK
202*fb1b10abSAndroid Build Coastguard Worker #define API_REGISTER_STATE_CHECK ASM_REGISTER_STATE_CHECK
203*fb1b10abSAndroid Build Coastguard Worker #endif
204*fb1b10abSAndroid Build Coastguard Worker 
205*fb1b10abSAndroid Build Coastguard Worker #endif  // VPX_TEST_REGISTER_STATE_CHECK_H_
206