[MemFunctions] Add validity check.

Summary: Validate the results in addition to benchmarking.

Reviewers: gchatelet

Subscribers: spatel, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D76056
diff --git a/MicroBenchmarks/MemFunctions/main.cpp b/MicroBenchmarks/MemFunctions/main.cpp
index 8ffdbb6..ea18445 100644
--- a/MicroBenchmarks/MemFunctions/main.cpp
+++ b/MicroBenchmarks/MemFunctions/main.cpp
@@ -17,11 +17,20 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include <cstdlib>
 #include <cstring>
+#include <iostream>
 #include <vector>
 
 #include "benchmark/benchmark.h"
 
+// This function prevents the compiler from interfering with `memcmp` and
+// makes sure the function is called.
+int RealMemCmp(const char *p, const char *q, size_t s)
+    __attribute__((no_builtin("memcmp"))) {
+  return memcmp(p, q, s);
+}
+
 // Benchmarks `memcmp(p, q, size) OP 0` where n is known at compile time and OP
 // is defined by `Pred`. The compiler typically inlines the memcmp + comparion
 // to loads and compares.
@@ -44,6 +53,13 @@
   for (int i = 0; i < kNumElements; ++i)
     Mod().template Change<kSize>(p + i * kSize);
 
+  // First check the validity of the results.
+  if (Pred::Cmp(RealMemCmp(p, q, kSize)) != Pred::Cmp(memcmp(p, q, kSize))) {
+    std::cerr << "invalid results for Pred=" << Pred::kDisplay
+              << " Mod=" << Mod::kDisplay << " kSize=" << kSize << std::endl;
+    std::exit(1);
+  }
+
   benchmark::DoNotOptimize(p);
   benchmark::DoNotOptimize(q);
 
@@ -52,7 +68,7 @@
     benchmark::ClobberMemory();
 
     for (int i = 0; i < kNumElements; ++i) {
-      int res = Pred()(memcmp(p + i * kSize, q + i * kSize, kSize));
+      bool res = Pred::Cmp(memcmp(p + i * kSize, q + i * kSize, kSize));
       benchmark::DoNotOptimize(res);
     }
   }
@@ -61,37 +77,35 @@
 
 // Predicates.
 struct EqZero {
-  bool operator()(int v) const { return v == 0; }
+  static bool Cmp(int v) { return v == 0; }
+  inline static constexpr const char kDisplay[] = "EqZero";
 };
 struct LessThanZero {
-  bool operator()(int v) const { return v < 0; }
+  static bool Cmp(int v) { return v < 0; }
+  inline static constexpr const char kDisplay[] = "LessThanZero";
 };
 struct GreaterThanZero {
-  bool operator()(int v) const { return v > 0; }
+  static bool Cmp(int v) { return v > 0; }
+  inline static constexpr const char kDisplay[] = "GreaterThanZero";
 };
 
 // Functors to change the first/mid/last or no value.
 struct None {
   template <int kSize>
   void Change(char* const p) const {}
+  inline static constexpr const char kDisplay[] = "None";
 };
 struct First {
-  template <int kSize>
-  void Change(char* const p) const {
-    p[0] = 128;
-  }
+  template <int kSize> void Change(char *const p) const { p[0] = 0xff; }
+  inline static constexpr const char kDisplay[] = "First";
 };
 struct Mid {
-  template <int kSize>
-  void Change(char* const p) const {
-    p[kSize / 2] = 128;
-  }
+  template <int kSize> void Change(char *const p) const { p[kSize / 2] = 0xff; }
+  inline static constexpr const char kDisplay[] = "Mid";
 };
 struct Last {
-  template <int kSize>
-  void Change(char* const p) const {
-    p[kSize - 1] = 128;
-  }
+  template <int kSize> void Change(char *const p) const { p[kSize - 1] = 0xff; }
+  inline static constexpr const char kDisplay[] = "Last";
 };
 
 #define MEMCMP_BENCHMARK_PRED_CHANGE(size, pred, change) \