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