tests: add xmm register check for win64 targets

Change-Id: I69d00bfd1b10c03581838b15cd9a6dd66f4fa416
diff --git a/test/decode_test_driver.cc b/test/decode_test_driver.cc
index 3610f025d..84afe7f 100644
--- a/test/decode_test_driver.cc
+++ b/test/decode_test_driver.cc
@@ -9,6 +9,7 @@
  */
 #include "test/decode_test_driver.h"
 #include "third_party/googletest/src/include/gtest/gtest.h"
+#include "test/register_state_check.h"
 #include "test/video_source.h"
 
 namespace libvpx_test {
@@ -21,8 +22,9 @@
     ASSERT_EQ(VPX_CODEC_OK, res_init) << DecodeError();
   }
 
-  const vpx_codec_err_t res_dec = vpx_codec_decode(&decoder_,
-                                                   cxdata, size, NULL, 0);
+  vpx_codec_err_t res_dec;
+  REGISTER_STATE_CHECK(res_dec = vpx_codec_decode(&decoder_,
+                                                  cxdata, size, NULL, 0));
   ASSERT_EQ(VPX_CODEC_OK, res_dec) << DecodeError();
 }
 
diff --git a/test/encode_test_driver.cc b/test/encode_test_driver.cc
index ebb3959..56339ca 100644
--- a/test/encode_test_driver.cc
+++ b/test/encode_test_driver.cc
@@ -12,6 +12,7 @@
 #if CONFIG_VP8_DECODER
 #include "test/decode_test_driver.h"
 #endif
+#include "test/register_state_check.h"
 #include "test/video_source.h"
 #include "third_party/googletest/src/include/gtest/gtest.h"
 
@@ -58,9 +59,10 @@
   }
 
   // Encode the frame
-  res = vpx_codec_encode(&encoder_,
-                         video.img(), video.pts(), video.duration(),
-                         frame_flags, deadline_);
+  REGISTER_STATE_CHECK(
+      res = vpx_codec_encode(&encoder_,
+                             video.img(), video.pts(), video.duration(),
+                             frame_flags, deadline_));
   ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
 }
 
diff --git a/test/idctllm_test.cc b/test/idctllm_test.cc
index dd42e22..1be5fa0 100644
--- a/test/idctllm_test.cc
+++ b/test/idctllm_test.cc
@@ -13,6 +13,7 @@
 #include "vpx_config.h"
 #include "vpx_rtcd.h"
 }
+#include "test/register_state_check.h"
 #include "third_party/googletest/src/include/gtest/gtest.h"
 
 typedef void (*idct_fn_t)(short *input, unsigned char *pred_ptr,
@@ -54,7 +55,7 @@
 {
     int i;
 
-    UUT(input, output, 16, output, 16);
+    REGISTER_STATE_CHECK(UUT(input, output, 16, output, 16));
 
     for(i=0; i<256; i++)
         if((i&0xF) < 4 && i<64)
@@ -68,7 +69,7 @@
     int i;
 
     input[0] = 4;
-    UUT(input, output, 16, output, 16);
+    REGISTER_STATE_CHECK(UUT(input, output, 16, output, 16));
 
     for(i=0; i<256; i++)
         if((i&0xF) < 4 && i<64)
@@ -85,7 +86,7 @@
         predict[i] = i;
 
     input[0] = 4;
-    UUT(input, predict, 16, output, 16);
+    REGISTER_STATE_CHECK(UUT(input, predict, 16, output, 16));
 
     for(i=0; i<256; i++)
         if((i&0xF) < 4 && i<64)
@@ -101,7 +102,7 @@
     for(i=0; i<16; i++)
         input[i] = i;
 
-    UUT(input, output, 16, output, 16);
+    REGISTER_STATE_CHECK(UUT(input, output, 16, output, 16));
 
     for(i=0; i<256; i++)
         if((i&0xF) > 3 || i>63)
diff --git a/test/intrapred_test.cc b/test/intrapred_test.cc
index d2e0d61..4c16c3f 100644
--- a/test/intrapred_test.cc
+++ b/test/intrapred_test.cc
@@ -11,6 +11,7 @@
 
 #include <string.h>
 #include "test/acm_random.h"
+#include "test/register_state_check.h"
 #include "third_party/googletest/src/include/gtest/gtest.h"
 extern "C" {
 #include "vpx_config.h"
@@ -246,8 +247,10 @@
 
   virtual void Predict(MB_PREDICTION_MODE mode) {
     mb_.mode_info_context->mbmi.mode = mode;
-    pred_fn_(&mb_, data_ptr_[0] - kStride, data_ptr_[0] - 1, kStride,
-             data_ptr_[0], kStride);
+    REGISTER_STATE_CHECK(pred_fn_(&mb_,
+                                  data_ptr_[0] - kStride,
+                                  data_ptr_[0] - 1, kStride,
+                                  data_ptr_[0], kStride));
   }
 
   intra_pred_y_fn_t pred_fn_;
diff --git a/test/pp_filter_test.cc b/test/pp_filter_test.cc
index af2f3bd..9227449 100644
--- a/test/pp_filter_test.cc
+++ b/test/pp_filter_test.cc
@@ -7,6 +7,7 @@
  *  in the file PATENTS.  All contributing project authors may
  *  be found in the AUTHORS file in the root of the source tree.
  */
+#include "test/register_state_check.h"
 #include "third_party/googletest/src/include/gtest/gtest.h"
 extern "C" {
 #include "vpx_config.h"
@@ -74,8 +75,8 @@
   // Initialize pixels in the output to 99.
   (void)vpx_memset(dst_image, 99, output_size);
 
-  GetParam()(src_image_ptr, dst_image_ptr, input_stride,
-             output_stride, block_width, flimits, 16);
+  REGISTER_STATE_CHECK(GetParam()(src_image_ptr, dst_image_ptr, input_stride,
+                                  output_stride, block_width, flimits, 16));
 
   static const uint8_t expected_data[block_height] = {
     4, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 4
diff --git a/test/register_state_check.h b/test/register_state_check.h
new file mode 100644
index 0000000..fb3f53b
--- /dev/null
+++ b/test/register_state_check.h
@@ -0,0 +1,95 @@
+/*
+ *  Copyright (c) 2012 The WebM project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef LIBVPX_TEST_REGISTER_STATE_CHECK_H_
+#define LIBVPX_TEST_REGISTER_STATE_CHECK_H_
+
+#ifdef _WIN64
+
+#define _WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <winnt.h>
+
+#include "third_party/googletest/src/include/gtest/gtest.h"
+
+namespace testing {
+namespace internal {
+
+inline bool operator==(const M128A& lhs, const M128A& rhs) {
+  return (lhs.Low == rhs.Low && lhs.High == rhs.High);
+}
+
+}  // namespace internal
+}  // namespace testing
+
+namespace libvpx_test {
+
+// Compares the state of xmm[6-15] at construction with their state at
+// destruction. These registers should be preserved by the callee on
+// Windows x64.
+// Usage:
+// {
+//   RegisterStateCheck reg_check;
+//   FunctionToVerify();
+// }
+class RegisterStateCheck {
+ public:
+  RegisterStateCheck() { initialized_ = StoreRegisters(&pre_context_); }
+  ~RegisterStateCheck() { EXPECT_TRUE(Check()); }
+
+ private:
+  static bool StoreRegisters(CONTEXT* const context) {
+    const HANDLE this_thread = GetCurrentThread();
+    EXPECT_TRUE(this_thread != NULL);
+    context->ContextFlags = CONTEXT_FLOATING_POINT;
+    const bool context_saved = GetThreadContext(this_thread, context) == TRUE;
+    EXPECT_TRUE(context_saved) << "GetLastError: " << GetLastError();
+    return context_saved;
+  }
+
+  // Compares the register state. Returns true if the states match.
+  bool Check() const {
+    if (!initialized_) return false;
+    CONTEXT post_context;
+    if (!StoreRegisters(&post_context)) return false;
+
+    const M128A* xmm_pre = &pre_context_.Xmm6;
+    const M128A* xmm_post = &post_context.Xmm6;
+    for (int i = 6; i <= 15; ++i) {
+      EXPECT_EQ(*xmm_pre, *xmm_post) << "xmm" << i << " has been modified!";
+      ++xmm_pre;
+      ++xmm_post;
+    }
+    return !testing::Test::HasNonfatalFailure();
+  }
+
+  bool initialized_;
+  CONTEXT pre_context_;
+};
+
+#define REGISTER_STATE_CHECK(statement) do { \
+  libvpx_test::RegisterStateCheck reg_check; \
+  statement;                               \
+} while (false)
+
+}  // namespace libvpx_test
+
+#else  // !_WIN64
+
+namespace libvpx_test {
+
+class RegisterStateCheck {};
+#define REGISTER_STATE_CHECK(statement) statement
+
+}  // namespace libvpx_test
+
+#endif  // _WIN64
+
+#endif  // LIBVPX_TEST_REGISTER_STATE_CHECK_H_
diff --git a/test/sad_test.cc b/test/sad_test.cc
index 2b562e6..5a0653b 100644
--- a/test/sad_test.cc
+++ b/test/sad_test.cc
@@ -21,6 +21,7 @@
 }
 
 #include "test/acm_random.h"
+#include "test/register_state_check.h"
 #include "test/util.h"
 #include "third_party/googletest/src/include/gtest/gtest.h"
 
@@ -65,9 +66,11 @@
 
   sad_m_by_n_fn_t sad_fn_;
   virtual unsigned int SAD(unsigned int max_sad) {
-    return sad_fn_(source_data_, source_stride_,
-                   reference_data_, reference_stride_,
-                   max_sad);
+    unsigned int ret;
+    REGISTER_STATE_CHECK(ret = sad_fn_(source_data_, source_stride_,
+                                       reference_data_, reference_stride_,
+                                       max_sad));
+    return ret;
   }
 
   // Sum of Absolute Differences. Given two blocks, calculate the absolute
diff --git a/test/sixtap_predict_test.cc b/test/sixtap_predict_test.cc
index 06f14a1..c9dcceb 100644
--- a/test/sixtap_predict_test.cc
+++ b/test/sixtap_predict_test.cc
@@ -12,6 +12,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include "test/acm_random.h"
+#include "test/register_state_check.h"
 #include "test/util.h"
 #include "third_party/googletest/src/include/gtest/gtest.h"
 extern "C" {
@@ -136,8 +137,8 @@
 
   uint8_t *src = const_cast<uint8_t*>(test_data);
 
-  sixtap_predict_(&src[kSrcStride * 2 + 2 + 1], kSrcStride,
-                  2, 2, dst_, kDstStride);
+  REGISTER_STATE_CHECK(sixtap_predict_(&src[kSrcStride * 2 + 2 + 1], kSrcStride,
+                                       2, 2, dst_, kDstStride));
 
   for (int i = 0; i < height_; ++i)
     for (int j = 0; j < width_; ++j)
@@ -162,8 +163,9 @@
                                 xoffset, yoffset, dst_c_, kDstStride);
 
       // Run test.
-      sixtap_predict_(&src_[kSrcStride * 2 + 2 + 1], kSrcStride,
-                      xoffset, yoffset, dst_, kDstStride);
+      REGISTER_STATE_CHECK(
+          sixtap_predict_(&src_[kSrcStride * 2 + 2 + 1], kSrcStride,
+                          xoffset, yoffset, dst_, kDstStride));
 
       for (int i = 0; i < height_; ++i)
         for (int j = 0; j < width_; ++j)
diff --git a/test/subtract_test.cc b/test/subtract_test.cc
index 99363de..60acf81 100644
--- a/test/subtract_test.cc
+++ b/test/subtract_test.cc
@@ -10,6 +10,7 @@
 
 #include "third_party/googletest/src/include/gtest/gtest.h"
 #include "test/acm_random.h"
+#include "test/register_state_check.h"
 extern "C" {
 #include "vpx_config.h"
 #include "vpx_rtcd.h"
@@ -77,7 +78,7 @@
       predictor += kDiffPredStride;
     }
 
-    GetParam()(&be, &bd, kDiffPredStride);
+    REGISTER_STATE_CHECK(GetParam()(&be, &bd, kDiffPredStride));
 
     base_src = *be.base_src;
     src_diff = be.src_diff;
diff --git a/test/test.mk b/test/test.mk
index 7a11a27..982be5b 100644
--- a/test/test.mk
+++ b/test/test.mk
@@ -1,4 +1,5 @@
 LIBVPX_TEST_SRCS-yes += acm_random.h
+LIBVPX_TEST_SRCS-yes += register_state_check.h
 LIBVPX_TEST_SRCS-yes += test.mk
 LIBVPX_TEST_SRCS-yes += test_libvpx.cc
 LIBVPX_TEST_SRCS-yes += util.h