[compiler-rt] 5136521 - Reapply "[compiler-rt][nsan] Add support for nan detection" (#105909)

Alexander Shaposhnikov via llvm-commits llvm-commits at lists.llvm.org
Sun Aug 25 03:34:00 PDT 2024


Author: Alexander Shaposhnikov
Date: 2024-08-25T10:17:36Z
New Revision: 51365212362c4d0e32a0c747ab85bbf3919944b8

URL: https://github.com/llvm/llvm-project/commit/51365212362c4d0e32a0c747ab85bbf3919944b8
DIFF: https://github.com/llvm/llvm-project/commit/51365212362c4d0e32a0c747ab85bbf3919944b8.diff

LOG: Reapply "[compiler-rt][nsan] Add support for nan detection" (#105909)

This reverts commit 1f89cd4a1970fee65f5ecb189c4d1a0a376d9bb2.

Added: 
    compiler-rt/test/nsan/nan.cpp
    compiler-rt/test/nsan/softmax.cpp
    compiler-rt/test/nsan/vec_sqrt.cpp
    compiler-rt/test/nsan/vec_sqrt_ext.cpp

Modified: 
    compiler-rt/lib/nsan/nsan.cpp
    compiler-rt/lib/nsan/nsan_flags.inc

Removed: 
    


################################################################################
diff  --git a/compiler-rt/lib/nsan/nsan.cpp b/compiler-rt/lib/nsan/nsan.cpp
index bfa55c317cfe79..ce161a18fa8f70 100644
--- a/compiler-rt/lib/nsan/nsan.cpp
+++ b/compiler-rt/lib/nsan/nsan.cpp
@@ -409,21 +409,21 @@ __nsan_dump_shadow_mem(const u8 *addr, size_t size_bytes, size_t bytes_per_line,
   }
 }
 
-alignas(16) SANITIZER_INTERFACE_ATTRIBUTE
+alignas(64) SANITIZER_INTERFACE_ATTRIBUTE
     thread_local uptr __nsan_shadow_ret_tag = 0;
 
-alignas(16) SANITIZER_INTERFACE_ATTRIBUTE
+alignas(64) SANITIZER_INTERFACE_ATTRIBUTE
     thread_local char __nsan_shadow_ret_ptr[kMaxVectorWidth *
                                             sizeof(__float128)];
 
-alignas(16) SANITIZER_INTERFACE_ATTRIBUTE
+alignas(64) SANITIZER_INTERFACE_ATTRIBUTE
     thread_local uptr __nsan_shadow_args_tag = 0;
 
 // Maximum number of args. This should be enough for anyone (tm). An alternate
 // scheme is to have the generated code create an alloca and make
 // __nsan_shadow_args_ptr point ot the alloca.
 constexpr const int kMaxNumArgs = 128;
-alignas(16) SANITIZER_INTERFACE_ATTRIBUTE
+alignas(64) SANITIZER_INTERFACE_ATTRIBUTE
     thread_local char __nsan_shadow_args_ptr[kMaxVectorWidth * kMaxNumArgs *
                                              sizeof(__float128)];
 
@@ -445,6 +445,32 @@ int32_t checkFT(const FT value, ShadowFT Shadow, CheckTypeT CheckType,
   const InternalFT check_value = value;
   const InternalFT check_shadow = Shadow;
 
+  // We only check for NaNs in the value, not the shadow.
+  if (flags().check_nan && isnan(check_value)) {
+    GET_CALLER_PC_BP;
+    BufferedStackTrace stack;
+    stack.Unwind(pc, bp, nullptr, false);
+    if (GetSuppressionForStack(&stack, CheckKind::Consistency)) {
+      // FIXME: optionally print.
+      return flags().resume_after_suppression ? kResumeFromValue
+                                              : kContinueWithShadow;
+    }
+    Decorator D;
+    Printf("%s", D.Warning());
+    Printf("WARNING: NumericalStabilitySanitizer: NaN detected\n");
+    Printf("%s", D.Default());
+    stack.Print();
+    if (flags().halt_on_error) {
+      if (common_flags()->abort_on_error)
+        Printf("ABORTING\n");
+      else
+        Printf("Exiting\n");
+      Die();
+    }
+    // Performing other tests for NaN values is meaningless when dealing with numbers.
+    return kResumeFromValue;
+  }
+
   // See this article for an interesting discussion of how to compare floats:
   // https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
   static constexpr const FT Eps = FTInfo<FT>::kEpsilon;

diff  --git a/compiler-rt/lib/nsan/nsan_flags.inc b/compiler-rt/lib/nsan/nsan_flags.inc
index 658cd5b3b01bf4..7c9e579d91fc33 100644
--- a/compiler-rt/lib/nsan/nsan_flags.inc
+++ b/compiler-rt/lib/nsan/nsan_flags.inc
@@ -48,3 +48,5 @@ NSAN_FLAG(bool, enable_loadtracking_stats, false,
           "due to invalid or unknown types.")
 NSAN_FLAG(bool, poison_in_free, true, "")
 NSAN_FLAG(bool, print_stats_on_exit, false, "If true, print stats on exit.")
+NSAN_FLAG(bool, check_nan, false,
+          "If true, check the floating-point number is nan")
\ No newline at end of file

diff  --git a/compiler-rt/test/nsan/nan.cpp b/compiler-rt/test/nsan/nan.cpp
new file mode 100644
index 00000000000000..59fc391a3e0a6b
--- /dev/null
+++ b/compiler-rt/test/nsan/nan.cpp
@@ -0,0 +1,25 @@
+// RUN: %clangxx_nsan -O0 -g %s -o %t
+// RUN: NSAN_OPTIONS=check_nan=true,halt_on_error=0 %run %t 2>&1 | FileCheck %s
+
+// RUN: %clangxx_nsan -O3 -g %s -o %t
+// RUN: NSAN_OPTIONS=check_nan=true,halt_on_error=0 %run %t 2>&1 | FileCheck %s
+
+// RUN: %clangxx_nsan -O0 -g %s -o %t
+// RUN: NSAN_OPTIONS=check_nan=true,halt_on_error=1 not %run %t
+
+#include <cmath>
+#include <cstdio>
+
+// This function returns a NaN value for triggering the NaN detection.
+__attribute__((noinline)) float ReturnNaN(float p, float q) {
+  float ret = p / q;
+  return ret;
+  // CHECK: WARNING: NumericalStabilitySanitizer: NaN detected
+}
+
+int main() {
+  float val = ReturnNaN(0., 0.);
+  printf("%f\n", val);
+  // CHECK: WARNING: NumericalStabilitySanitizer: NaN detected
+  return 0;
+}

diff  --git a/compiler-rt/test/nsan/softmax.cpp b/compiler-rt/test/nsan/softmax.cpp
new file mode 100644
index 00000000000000..29eaa2f9607a20
--- /dev/null
+++ b/compiler-rt/test/nsan/softmax.cpp
@@ -0,0 +1,54 @@
+// RUN: %clangxx_nsan -O0 -g -DSOFTMAX=softmax %s -o %t
+// RUN: NSAN_OPTIONS=check_nan=true,halt_on_error=0,log2_max_relative_error=19 %run %t 2>&1 | FileCheck %s
+
+// RUN: %clangxx_nsan -O3 -g -DSOFTMAX=softmax %s -o %t
+// RUN: NSAN_OPTIONS=check_nan=true,halt_on_error=0,log2_max_relative_error=19 %run %t 2>&1 | FileCheck %s
+
+// RUN: %clangxx_nsan -O0 -g -DSOFTMAX=stable_softmax %s -o %t
+// RUN: NSAN_OPTIONS=check_nan=true,halt_on_error=1,log2_max_relative_error=19 %run %t 
+
+// RUN: %clangxx_nsan -O3 -g -DSOFTMAX=stable_softmax %s -o %t
+// RUN: NSAN_OPTIONS=check_nan=true,halt_on_error=1,log2_max_relative_error=19 %run %t
+
+#include<iostream>
+#include<vector>
+#include<algorithm>
+#include<cmath>
+
+// unstable softmax
+template <typename T>
+__attribute__((noinline)) void softmax(std::vector<T> &values) {
+    T sum_exp = 0.0;
+    for (auto &i: values) {
+      i = std::exp(i);
+      sum_exp += i;
+    }
+    for (auto &i: values) {
+      i /= sum_exp;
+    }
+}
+
+// use max value to avoid overflow
+// \sigma_i exp(x_i) / \sum_j exp(x_j) = \sigma_i exp(x_i - max(x)) / \sum_j exp(x_j - max(x))
+template <typename T>
+__attribute__((noinline)) void stable_softmax(std::vector<T> &values) {
+  T sum_exp = 0.0;
+  T max_values = *std::max_element(values.begin(), values.end());
+  for (auto &i: values) {
+    i = std::exp(i - max_values);
+    sum_exp += i;
+  }
+  for (auto &i:values) {
+    i /= sum_exp;
+  }
+}
+
+int main() {
+  std::vector<double> data = {1000, 1001, 1002};
+  SOFTMAX(data);
+  for (auto i: data) {
+    printf("%f", i);
+    // CHECK: WARNING: NumericalStabilitySanitizer: NaN detected
+  }
+  return 0;
+}
\ No newline at end of file

diff  --git a/compiler-rt/test/nsan/vec_sqrt.cpp b/compiler-rt/test/nsan/vec_sqrt.cpp
new file mode 100644
index 00000000000000..d1ef0487858506
--- /dev/null
+++ b/compiler-rt/test/nsan/vec_sqrt.cpp
@@ -0,0 +1,34 @@
+// RUN: %clangxx_nsan -O0 -g -mavx %s -o %t
+// RUN: NSAN_OPTIONS=check_nan=true,halt_on_error=0 %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_nsan -O3 -g -mavx %s -o %t
+// RUN: NSAN_OPTIONS=check_nan=true,halt_on_error=0 %run %t 2>&1 | FileCheck %s
+
+#include <cmath>
+#include <immintrin.h>
+#include <iostream>
+
+void simd_sqrt(const float *input, float *output, size_t size) {
+  size_t i = 0;
+  for (; i + 7 < size; i += 8) {
+    __m256 vec = _mm256_loadu_ps(&input[i]);
+    __m256 result = _mm256_sqrt_ps(vec);
+    _mm256_storeu_ps(&output[i], result);
+  }
+  for (; i < size; ++i) {
+    output[i] = std::sqrt(input[i]);
+    // CHECK: WARNING: NumericalStabilitySanitizer: NaN detected
+  }
+}
+
+int main() {
+  float input[] = {1.0,  2.0,   -3.0,  4.0,   5.0,   6.0,  7.0,
+                   8.0,  9.0,   -10.0, 11.0,  12.0,  13.0, 14.0,
+                   15.0, -16.0, 17.0,  -18.0, -19.0, -20.0};
+  float output[20];
+  simd_sqrt(input, output, 20);
+  for (int i = 0; i < 20; ++i) {
+    std::cout << output[i] << std::endl;
+    // CHECK: WARNING: NumericalStabilitySanitizer: NaN detected
+  }
+  return 0;
+}
\ No newline at end of file

diff  --git a/compiler-rt/test/nsan/vec_sqrt_ext.cpp b/compiler-rt/test/nsan/vec_sqrt_ext.cpp
new file mode 100644
index 00000000000000..b39ce4b99bcab6
--- /dev/null
+++ b/compiler-rt/test/nsan/vec_sqrt_ext.cpp
@@ -0,0 +1,25 @@
+// RUN: %clangxx_nsan -O0 -g -mavx %s -o %t
+// RUN: NSAN_OPTIONS=check_nan=true,halt_on_error=0 %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_nsan -O3 -g -mavx %s -o %t
+// RUN: NSAN_OPTIONS=check_nan=true,halt_on_error=0 %run %t 2>&1 | FileCheck %s
+#include <iostream>
+#include <cmath>
+
+typedef float v8sf __attribute__ ((vector_size(32)));
+
+v8sf simd_sqrt(v8sf a) {
+  return __builtin_elementwise_sqrt(a);
+  // CHECK: WARNING: NumericalStabilitySanitizer: NaN detected
+}
+
+int main() {
+  v8sf a = {-1.0, -2.0, -3.0, 4.0, 5.0, 6.0, 7.0, 8.0};
+  a = simd_sqrt(a);
+
+  // This prevents DCE.
+  for (size_t i = 0; i < 8; ++i) {
+    std::cout << a[i] << std::endl;
+    // CHECK: WARNING: NumericalStabilitySanitizer: NaN detected
+  }
+  return 0;
+}
\ No newline at end of file


        


More information about the llvm-commits mailing list