Add DoNotOptimize and use it in tests.

Bug: http://b/148307629
Test: treehugger
Change-Id: I3b1726ae55116f6553ea38fe163abdde179c21f0
diff --git a/tests/fenv_test.cpp b/tests/fenv_test.cpp
index e983a1c..89c7fd5 100644
--- a/tests/fenv_test.cpp
+++ b/tests/fenv_test.cpp
@@ -22,19 +22,20 @@
 #include <stdint.h>
 
 static void TestRounding(float expectation1, float expectation2) {
-  // volatile to prevent compiler optimizations.
+  // Volatile to prevent compile-time evaluation.
   volatile float f = 1.968750f;
   volatile float m = 0x1.0p23f;
-  volatile float x = f + m;
+  float x;
+  DoNotOptimize(x = f + m);
   ASSERT_FLOAT_EQ(expectation1, x);
-  x = x - m;
+  DoNotOptimize(x = x - m);
   ASSERT_EQ(expectation2, x);
 }
 
 static void DivideByZero() {
-  // volatile to prevent compiler optimizations.
+  // Volatile to prevent compile-time evaluation.
   volatile float zero = 0.0f;
-  volatile float result __attribute__((unused)) = 123.0f / zero;
+  DoNotOptimize(123.0f / zero);
 }
 
 TEST(fenv, fesetround_fegetround_FE_TONEAREST) {
diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp
index 4ea6d2b..ddd3416 100644
--- a/tests/malloc_test.cpp
+++ b/tests/malloc_test.cpp
@@ -925,12 +925,8 @@
     std::thread* t = new std::thread([&stop] {
       while (!stop) {
         for (size_t size = kMinAllocationSize; size <= kMaxAllocationSize; size <<= 1) {
-          void* ptr = malloc(size);
-          if (ptr == nullptr) {
-            return;
-          }
-          // Make sure this value is not optimized away.
-          asm volatile("" : : "r,m"(ptr) : "memory");
+          void* ptr;
+          DoNotOptimize(ptr = malloc(size));
           free(ptr);
         }
       }
@@ -943,10 +939,9 @@
     pid_t pid;
     if ((pid = fork()) == 0) {
       for (size_t size = kMinAllocationSize; size <= kMaxAllocationSize; size <<= 1) {
-        void* ptr = malloc(size);
+        void* ptr;
+        DoNotOptimize(ptr = malloc(size));
         ASSERT_TRUE(ptr != nullptr);
-        // Make sure this value is not optimized away.
-        asm volatile("" : : "r,m"(ptr) : "memory");
         // Make sure we can touch all of the allocation.
         memset(ptr, 0x1, size);
         ASSERT_LE(size, malloc_usable_size(ptr));
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index 43d50f8..41ca8b4 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -676,14 +676,10 @@
   ASSERT_NE(static_cast<uint64_t>(parent_tid), reinterpret_cast<uint64_t>(result));
 }
 
-static void optimization_barrier(void* arg) {
-  asm volatile("" : : "r"(arg) : "memory");
-}
-
 __attribute__((noinline)) static void HwasanVforkTestChild() {
   // Allocate a tagged region on stack and leave it there.
   char x[10000];
-  optimization_barrier(x);
+  DoNotOptimize(x);
   _exit(0);
 }
 
@@ -700,7 +696,7 @@
   // Allocate a region on stack, but don't tag it (see the function attribute).
   // This depends on unallocated stack space at current function entry being untagged.
   char x[10000];
-  optimization_barrier(x);
+  DoNotOptimize(x);
   // Verify that contents of x[] are untagged.
   HwasanReadMemory(x, sizeof(x));
 }
diff --git a/tests/utils.h b/tests/utils.h
index acd8bc6..94ff050 100644
--- a/tests/utils.h
+++ b/tests/utils.h
@@ -290,3 +290,13 @@
 
   size_t start_count_ = CountOpenFds();
 };
+
+// From <benchmark/benchmark.h>.
+template <class Tp>
+static inline void DoNotOptimize(Tp const& value) {
+  asm volatile("" : : "r,m"(value) : "memory");
+}
+template <class Tp>
+static inline void DoNotOptimize(Tp& value) {
+  asm volatile("" : "+r,m"(value) : : "memory");
+}