register_state_check.h 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  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. #ifndef TEST_REGISTER_STATE_CHECK_H_
  11. #define TEST_REGISTER_STATE_CHECK_H_
  12. #include "third_party/googletest/src/include/gtest/gtest.h"
  13. #include "./vpx_config.h"
  14. #include "vpx/vpx_integer.h"
  15. // ASM_REGISTER_STATE_CHECK(asm_function)
  16. // Minimally validates the environment pre & post function execution. This
  17. // variant should be used with assembly functions which are not expected to
  18. // fully restore the system state. See platform implementations of
  19. // RegisterStateCheck for details.
  20. //
  21. // API_REGISTER_STATE_CHECK(api_function)
  22. // Performs all the checks done by ASM_REGISTER_STATE_CHECK() and any
  23. // additional checks to ensure the environment is in a consistent state pre &
  24. // post function execution. This variant should be used with API functions.
  25. // See platform implementations of RegisterStateCheckXXX for details.
  26. //
  27. #if defined(_WIN64)
  28. #undef NOMINMAX
  29. #define NOMINMAX
  30. #ifndef WIN32_LEAN_AND_MEAN
  31. #define WIN32_LEAN_AND_MEAN
  32. #endif
  33. #include <windows.h>
  34. #include <winnt.h>
  35. inline bool operator==(const M128A &lhs, const M128A &rhs) {
  36. return (lhs.Low == rhs.Low && lhs.High == rhs.High);
  37. }
  38. namespace libvpx_test {
  39. // Compares the state of xmm[6-15] at construction with their state at
  40. // destruction. These registers should be preserved by the callee on
  41. // Windows x64.
  42. class RegisterStateCheck {
  43. public:
  44. RegisterStateCheck() { initialized_ = StoreRegisters(&pre_context_); }
  45. ~RegisterStateCheck() { Check(); }
  46. private:
  47. static bool StoreRegisters(CONTEXT *const context) {
  48. const HANDLE this_thread = GetCurrentThread();
  49. EXPECT_TRUE(this_thread != NULL);
  50. context->ContextFlags = CONTEXT_FLOATING_POINT;
  51. const bool context_saved = GetThreadContext(this_thread, context) == TRUE;
  52. EXPECT_TRUE(context_saved) << "GetLastError: " << GetLastError();
  53. return context_saved;
  54. }
  55. // Compares the register state. Returns true if the states match.
  56. void Check() const {
  57. ASSERT_TRUE(initialized_);
  58. CONTEXT post_context;
  59. ASSERT_TRUE(StoreRegisters(&post_context));
  60. const M128A *xmm_pre = &pre_context_.Xmm6;
  61. const M128A *xmm_post = &post_context.Xmm6;
  62. for (int i = 6; i <= 15; ++i) {
  63. EXPECT_EQ(*xmm_pre, *xmm_post) << "xmm" << i << " has been modified!";
  64. ++xmm_pre;
  65. ++xmm_post;
  66. }
  67. }
  68. bool initialized_;
  69. CONTEXT pre_context_;
  70. };
  71. #define ASM_REGISTER_STATE_CHECK(statement) \
  72. do { \
  73. libvpx_test::RegisterStateCheck reg_check; \
  74. statement; \
  75. } while (false)
  76. } // namespace libvpx_test
  77. #elif defined(CONFIG_SHARED) && defined(HAVE_NEON_ASM) && \
  78. defined(CONFIG_VP9) && !CONFIG_SHARED && HAVE_NEON_ASM && CONFIG_VP9
  79. extern "C" {
  80. // Save the d8-d15 registers into store.
  81. void vpx_push_neon(int64_t *store);
  82. }
  83. namespace libvpx_test {
  84. // Compares the state of d8-d15 at construction with their state at
  85. // destruction. These registers should be preserved by the callee on
  86. // arm platform.
  87. class RegisterStateCheck {
  88. public:
  89. RegisterStateCheck() { vpx_push_neon(pre_store_); }
  90. ~RegisterStateCheck() { Check(); }
  91. private:
  92. // Compares the register state. Returns true if the states match.
  93. void Check() const {
  94. int64_t post_store[8];
  95. vpx_push_neon(post_store);
  96. for (int i = 0; i < 8; ++i) {
  97. EXPECT_EQ(pre_store_[i], post_store[i])
  98. << "d" << i + 8 << " has been modified";
  99. }
  100. }
  101. int64_t pre_store_[8];
  102. };
  103. #define ASM_REGISTER_STATE_CHECK(statement) \
  104. do { \
  105. libvpx_test::RegisterStateCheck reg_check; \
  106. statement; \
  107. } while (false)
  108. } // namespace libvpx_test
  109. #else
  110. namespace libvpx_test {
  111. class RegisterStateCheck {};
  112. #define ASM_REGISTER_STATE_CHECK(statement) statement
  113. } // namespace libvpx_test
  114. #endif // _WIN64
  115. #if ARCH_X86 || ARCH_X86_64
  116. #if defined(__GNUC__)
  117. namespace libvpx_test {
  118. // Checks the FPU tag word pre/post execution to ensure emms has been called.
  119. class RegisterStateCheckMMX {
  120. public:
  121. RegisterStateCheckMMX() {
  122. __asm__ volatile("fstenv %0" : "=rm"(pre_fpu_env_));
  123. }
  124. ~RegisterStateCheckMMX() { Check(); }
  125. private:
  126. // Checks the FPU tag word pre/post execution, returning false if not cleared
  127. // to 0xffff.
  128. void Check() const {
  129. EXPECT_EQ(0xffff, pre_fpu_env_[4])
  130. << "FPU was in an inconsistent state prior to call";
  131. uint16_t post_fpu_env[14];
  132. __asm__ volatile("fstenv %0" : "=rm"(post_fpu_env));
  133. EXPECT_EQ(0xffff, post_fpu_env[4])
  134. << "FPU was left in an inconsistent state after call";
  135. }
  136. uint16_t pre_fpu_env_[14];
  137. };
  138. #define API_REGISTER_STATE_CHECK(statement) \
  139. do { \
  140. libvpx_test::RegisterStateCheckMMX reg_check; \
  141. ASM_REGISTER_STATE_CHECK(statement); \
  142. } while (false)
  143. } // namespace libvpx_test
  144. #endif // __GNUC__
  145. #endif // ARCH_X86 || ARCH_X86_64
  146. #ifndef API_REGISTER_STATE_CHECK
  147. #define API_REGISTER_STATE_CHECK ASM_REGISTER_STATE_CHECK
  148. #endif
  149. #endif // TEST_REGISTER_STATE_CHECK_H_