Skip to content

Conversation

alexander-shaposhnikov
Copy link
Collaborator

Add plumbing for the numerical sanitizer on Clang's side.
This patch was extracted from #85916

Test plan: ninja check-all

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:codegen IR generation bugs: mangling, exceptions, etc. llvm:ir labels May 30, 2024
@llvmbot
Copy link
Member

llvmbot commented May 30, 2024

@llvm/pr-subscribers-clang-driver
@llvm/pr-subscribers-clang

@llvm/pr-subscribers-llvm-ir

Author: Alexander Shaposhnikov (alexander-shaposhnikov)

Changes

Add plumbing for the numerical sanitizer on Clang's side.
This patch was extracted from #85916

Test plan: ninja check-all


Full diff: https://github.com/llvm/llvm-project/pull/93783.diff

10 Files Affected:

  • (modified) clang/include/clang/Basic/Features.def (+1)
  • (modified) clang/include/clang/Basic/Sanitizers.def (+3)
  • (modified) clang/include/clang/Driver/SanitizerArgs.h (+3)
  • (modified) clang/lib/CodeGen/CGDeclCXX.cpp (+4)
  • (modified) clang/lib/CodeGen/CodeGenFunction.cpp (+2)
  • (modified) clang/lib/Driver/SanitizerArgs.cpp (+5-2)
  • (modified) clang/lib/Driver/ToolChains/Linux.cpp (+4)
  • (added) clang/test/CodeGen/sanitize-numerical-stability-attr.cpp (+49)
  • (added) clang/test/Lexer/has_feature_numerical_stability_sanitizer.cpp (+11)
  • (modified) llvm/include/llvm/IR/Attributes.td (+3)
diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def
index b762e44e755ec..53f410d3cb4bd 100644
--- a/clang/include/clang/Basic/Features.def
+++ b/clang/include/clang/Basic/Features.def
@@ -96,6 +96,7 @@ FEATURE(nullability, true)
 FEATURE(nullability_on_arrays, true)
 FEATURE(nullability_on_classes, true)
 FEATURE(nullability_nullable_result, true)
+FEATURE(numerical_stability_sanitizer, LangOpts.Sanitize.has(SanitizerKind::NumericalStability))
 FEATURE(memory_sanitizer,
         LangOpts.Sanitize.hasOneOf(SanitizerKind::Memory |
                                    SanitizerKind::KernelMemory))
diff --git a/clang/include/clang/Basic/Sanitizers.def b/clang/include/clang/Basic/Sanitizers.def
index b228ffd07ee74..bee35e9dca7c3 100644
--- a/clang/include/clang/Basic/Sanitizers.def
+++ b/clang/include/clang/Basic/Sanitizers.def
@@ -76,6 +76,9 @@ SANITIZER("fuzzer-no-link", FuzzerNoLink)
 // ThreadSanitizer
 SANITIZER("thread", Thread)
 
+// Numerical stability sanitizer.
+SANITIZER("numerical", NumericalStability)
+
 // LeakSanitizer
 SANITIZER("leak", Leak)
 
diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h
index 07070ec4fc065..47ef175302679 100644
--- a/clang/include/clang/Driver/SanitizerArgs.h
+++ b/clang/include/clang/Driver/SanitizerArgs.h
@@ -103,6 +103,9 @@ class SanitizerArgs {
   bool needsCfiDiagRt() const;
   bool needsStatsRt() const { return Stats; }
   bool needsScudoRt() const { return Sanitizers.has(SanitizerKind::Scudo); }
+  bool needsNsanRt() const {
+    return Sanitizers.has(SanitizerKind::NumericalStability);
+  }
 
   bool hasMemTag() const {
     return hasMemtagHeap() || hasMemtagStack() || hasMemtagGlobals();
diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp
index b047279912f6b..a88bb2af59fee 100644
--- a/clang/lib/CodeGen/CGDeclCXX.cpp
+++ b/clang/lib/CodeGen/CGDeclCXX.cpp
@@ -476,6 +476,10 @@ llvm::Function *CodeGenModule::CreateGlobalInitOrCleanUpFunction(
       !isInNoSanitizeList(SanitizerKind::Thread, Fn, Loc))
     Fn->addFnAttr(llvm::Attribute::SanitizeThread);
 
+  if (getLangOpts().Sanitize.has(SanitizerKind::NumericalStability) &&
+      !isInNoSanitizeList(SanitizerKind::NumericalStability, Fn, Loc))
+    Fn->addFnAttr(llvm::Attribute::SanitizeNumericalStability);
+
   if (getLangOpts().Sanitize.has(SanitizerKind::Memory) &&
       !isInNoSanitizeList(SanitizerKind::Memory, Fn, Loc))
     Fn->addFnAttr(llvm::Attribute::SanitizeMemory);
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index f0345f3b191b8..681ecfda004d4 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -818,6 +818,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
       Fn->addFnAttr(llvm::Attribute::SanitizeMemTag);
     if (SanOpts.has(SanitizerKind::Thread))
       Fn->addFnAttr(llvm::Attribute::SanitizeThread);
+    if (SanOpts.has(SanitizerKind::NumericalStability))
+      Fn->addFnAttr(llvm::Attribute::SanitizeNumericalStability);
     if (SanOpts.hasOneOf(SanitizerKind::Memory | SanitizerKind::KernelMemory))
       Fn->addFnAttr(llvm::Attribute::SanitizeMemory);
   }
diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp
index 273f215ca94a8..86825a6ccf7a1 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -41,7 +41,8 @@ static const SanitizerMask NotAllowedWithExecuteOnly =
     SanitizerKind::Function | SanitizerKind::KCFI;
 static const SanitizerMask NeedsUnwindTables =
     SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Thread |
-    SanitizerKind::Memory | SanitizerKind::DataFlow;
+    SanitizerKind::Memory | SanitizerKind::DataFlow |
+    SanitizerKind::NumericalStability;
 static const SanitizerMask SupportsCoverage =
     SanitizerKind::Address | SanitizerKind::HWAddress |
     SanitizerKind::KernelAddress | SanitizerKind::KernelHWAddress |
@@ -53,7 +54,8 @@ static const SanitizerMask SupportsCoverage =
     SanitizerKind::DataFlow | SanitizerKind::Fuzzer |
     SanitizerKind::FuzzerNoLink | SanitizerKind::FloatDivideByZero |
     SanitizerKind::SafeStack | SanitizerKind::ShadowCallStack |
-    SanitizerKind::Thread | SanitizerKind::ObjCCast | SanitizerKind::KCFI;
+    SanitizerKind::Thread | SanitizerKind::ObjCCast | SanitizerKind::KCFI |
+    SanitizerKind::NumericalStability;
 static const SanitizerMask RecoverableByDefault =
     SanitizerKind::Undefined | SanitizerKind::Integer |
     SanitizerKind::ImplicitConversion | SanitizerKind::Nullability |
@@ -175,6 +177,7 @@ static void addDefaultIgnorelists(const Driver &D, SanitizerMask Kinds,
                      {"hwasan_ignorelist.txt", SanitizerKind::HWAddress},
                      {"memtag_ignorelist.txt", SanitizerKind::MemTag},
                      {"msan_ignorelist.txt", SanitizerKind::Memory},
+                     {"nsan_ignorelist.txt", SanitizerKind::NumericalStability},
                      {"tsan_ignorelist.txt", SanitizerKind::Thread},
                      {"dfsan_abilist.txt", SanitizerKind::DataFlow},
                      {"cfi_ignorelist.txt", SanitizerKind::CFI},
diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp
index db2c20d7b461d..3ecf57a94ea89 100644
--- a/clang/lib/Driver/ToolChains/Linux.cpp
+++ b/clang/lib/Driver/ToolChains/Linux.cpp
@@ -826,6 +826,10 @@ SanitizerMask Linux::getSupportedSanitizers() const {
   if (IsX86_64 || IsAArch64) {
     Res |= SanitizerKind::KernelHWAddress;
   }
+  if (IsX86_64) {
+    Res |= SanitizerKind::NumericalStability;
+  }
+
   // Work around "Cannot represent a difference across sections".
   if (getTriple().getArch() == llvm::Triple::ppc64)
     Res &= ~SanitizerKind::Function;
diff --git a/clang/test/CodeGen/sanitize-numerical-stability-attr.cpp b/clang/test/CodeGen/sanitize-numerical-stability-attr.cpp
new file mode 100644
index 0000000000000..56634c54962f4
--- /dev/null
+++ b/clang/test/CodeGen/sanitize-numerical-stability-attr.cpp
@@ -0,0 +1,49 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s | FileCheck -check-prefix=WITHOUT %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=numerical | FileCheck -check-prefix=NSAN %s
+// RUN: echo "src:%s" | sed -e 's/\\/\\\\/g' > %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=numerical -fsanitize-ignorelist=%t | FileCheck -check-prefix=BL %s
+
+// The sanitize_numerical_stability attribute should be attached to functions
+// when ThreadSanitizer is enabled, unless no_sanitize_numerical_stability attribute
+// is present.
+
+// WITHOUT:  NoNSAN1{{.*}}) [[NOATTR:#[0-9]+]]
+// BL:  NoNSAN1{{.*}}) [[NOATTR:#[0-9]+]]
+// NSAN:  NoNSAN1{{.*}}) [[NOATTR:#[0-9]+]]
+__attribute__((no_sanitize_numerical_stability))
+int NoNSAN1(int *a) { return *a; }
+
+// WITHOUT:  NoNSAN2{{.*}}) [[NOATTR]]
+// BL:  NoNSAN2{{.*}}) [[NOATTR]]
+// NSAN:  NoNSAN2{{.*}}) [[NOATTR]]
+__attribute__((no_sanitize_numerical_stability))
+int NoNSAN2(int *a);
+int NoNSAN2(int *a) { return *a; }
+
+// WITHOUT:  NoNSAN3{{.*}}) [[NOATTR:#[0-9]+]]
+// BL:  NoNSAN3{{.*}}) [[NOATTR:#[0-9]+]]
+// NSAN:  NoNSAN3{{.*}}) [[NOATTR:#[0-9]+]]
+__attribute__((no_sanitize("thread")))
+int NoNSAN3(int *a) { return *a; }
+
+// WITHOUT:  NSANOk{{.*}}) [[NOATTR]]
+// BL:  NSANOk{{.*}}) [[NOATTR]]
+// NSAN: NSANOk{{.*}}) [[WITH:#[0-9]+]]
+int NSANOk(int *a) { return *a; }
+
+// WITHOUT:  TemplateNSANOk{{.*}}) [[NOATTR]]
+// BL:  TemplateNSANOk{{.*}}) [[NOATTR]]
+// NSAN: TemplateNSANOk{{.*}}) [[WITH]]
+template<int i>
+int TemplateNSANOk() { return i; }
+
+// WITHOUT:  TemplateNoNSAN{{.*}}) [[NOATTR]]
+// BL:  TemplateNoNSAN{{.*}}) [[NOATTR]]
+// NSAN: TemplateNoNSAN{{.*}}) [[NOATTR]]
+template<int i>
+__attribute__((no_sanitize_numerical_stability))
+int TemplateNoNSAN() { return i; }
+
+int force_instance = TemplateNSANOk<42>()
+                   + TemplateNoNSAN<42>();
+
diff --git a/clang/test/Lexer/has_feature_numerical_stability_sanitizer.cpp b/clang/test/Lexer/has_feature_numerical_stability_sanitizer.cpp
new file mode 100644
index 0000000000000..78884977322b8
--- /dev/null
+++ b/clang/test/Lexer/has_feature_numerical_stability_sanitizer.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -E -fsanitize=numerical %s -o - | FileCheck --check-prefix=CHECK-NSAN %s
+// RUN: %clang_cc1 -E  %s -o - | FileCheck --check-prefix=CHECK-NO-NSAN %s
+
+#if __has_feature(numerical_stability_sanitizer)
+int NumericalStabilitySanitizerEnabled();
+#else
+int NumericalStabilitySanitizerDisabled();
+#endif
+
+// CHECK-NSAN: NumericalStabilitySanitizerEnabled
+// CHECK-NO-NSAN: NumericalStabilitySanitizerDisabled
diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td
index cef8b17769f0d..00ec7393c2265 100644
--- a/llvm/include/llvm/IR/Attributes.td
+++ b/llvm/include/llvm/IR/Attributes.td
@@ -285,6 +285,9 @@ def SanitizeHWAddress : EnumAttr<"sanitize_hwaddress", [FnAttr]>;
 /// MemTagSanitizer is on.
 def SanitizeMemTag : EnumAttr<"sanitize_memtag", [FnAttr]>;
 
+/// NumericalStabilitySanitizer is on.
+def SanitizeNumericalStability : EnumAttr<"sanitize_numericalstability", [FnAttr]>;
+
 /// Speculative Load Hardening is enabled.
 ///
 /// Note that this uses the default compatibility (always compatible during

@llvmbot
Copy link
Member

llvmbot commented May 30, 2024

@llvm/pr-subscribers-clang-codegen

Author: Alexander Shaposhnikov (alexander-shaposhnikov)

Changes

Add plumbing for the numerical sanitizer on Clang's side.
This patch was extracted from #85916

Test plan: ninja check-all


Full diff: https://github.com/llvm/llvm-project/pull/93783.diff

10 Files Affected:

  • (modified) clang/include/clang/Basic/Features.def (+1)
  • (modified) clang/include/clang/Basic/Sanitizers.def (+3)
  • (modified) clang/include/clang/Driver/SanitizerArgs.h (+3)
  • (modified) clang/lib/CodeGen/CGDeclCXX.cpp (+4)
  • (modified) clang/lib/CodeGen/CodeGenFunction.cpp (+2)
  • (modified) clang/lib/Driver/SanitizerArgs.cpp (+5-2)
  • (modified) clang/lib/Driver/ToolChains/Linux.cpp (+4)
  • (added) clang/test/CodeGen/sanitize-numerical-stability-attr.cpp (+49)
  • (added) clang/test/Lexer/has_feature_numerical_stability_sanitizer.cpp (+11)
  • (modified) llvm/include/llvm/IR/Attributes.td (+3)
diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def
index b762e44e755ec..53f410d3cb4bd 100644
--- a/clang/include/clang/Basic/Features.def
+++ b/clang/include/clang/Basic/Features.def
@@ -96,6 +96,7 @@ FEATURE(nullability, true)
 FEATURE(nullability_on_arrays, true)
 FEATURE(nullability_on_classes, true)
 FEATURE(nullability_nullable_result, true)
+FEATURE(numerical_stability_sanitizer, LangOpts.Sanitize.has(SanitizerKind::NumericalStability))
 FEATURE(memory_sanitizer,
         LangOpts.Sanitize.hasOneOf(SanitizerKind::Memory |
                                    SanitizerKind::KernelMemory))
diff --git a/clang/include/clang/Basic/Sanitizers.def b/clang/include/clang/Basic/Sanitizers.def
index b228ffd07ee74..bee35e9dca7c3 100644
--- a/clang/include/clang/Basic/Sanitizers.def
+++ b/clang/include/clang/Basic/Sanitizers.def
@@ -76,6 +76,9 @@ SANITIZER("fuzzer-no-link", FuzzerNoLink)
 // ThreadSanitizer
 SANITIZER("thread", Thread)
 
+// Numerical stability sanitizer.
+SANITIZER("numerical", NumericalStability)
+
 // LeakSanitizer
 SANITIZER("leak", Leak)
 
diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h
index 07070ec4fc065..47ef175302679 100644
--- a/clang/include/clang/Driver/SanitizerArgs.h
+++ b/clang/include/clang/Driver/SanitizerArgs.h
@@ -103,6 +103,9 @@ class SanitizerArgs {
   bool needsCfiDiagRt() const;
   bool needsStatsRt() const { return Stats; }
   bool needsScudoRt() const { return Sanitizers.has(SanitizerKind::Scudo); }
+  bool needsNsanRt() const {
+    return Sanitizers.has(SanitizerKind::NumericalStability);
+  }
 
   bool hasMemTag() const {
     return hasMemtagHeap() || hasMemtagStack() || hasMemtagGlobals();
diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp
index b047279912f6b..a88bb2af59fee 100644
--- a/clang/lib/CodeGen/CGDeclCXX.cpp
+++ b/clang/lib/CodeGen/CGDeclCXX.cpp
@@ -476,6 +476,10 @@ llvm::Function *CodeGenModule::CreateGlobalInitOrCleanUpFunction(
       !isInNoSanitizeList(SanitizerKind::Thread, Fn, Loc))
     Fn->addFnAttr(llvm::Attribute::SanitizeThread);
 
+  if (getLangOpts().Sanitize.has(SanitizerKind::NumericalStability) &&
+      !isInNoSanitizeList(SanitizerKind::NumericalStability, Fn, Loc))
+    Fn->addFnAttr(llvm::Attribute::SanitizeNumericalStability);
+
   if (getLangOpts().Sanitize.has(SanitizerKind::Memory) &&
       !isInNoSanitizeList(SanitizerKind::Memory, Fn, Loc))
     Fn->addFnAttr(llvm::Attribute::SanitizeMemory);
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index f0345f3b191b8..681ecfda004d4 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -818,6 +818,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
       Fn->addFnAttr(llvm::Attribute::SanitizeMemTag);
     if (SanOpts.has(SanitizerKind::Thread))
       Fn->addFnAttr(llvm::Attribute::SanitizeThread);
+    if (SanOpts.has(SanitizerKind::NumericalStability))
+      Fn->addFnAttr(llvm::Attribute::SanitizeNumericalStability);
     if (SanOpts.hasOneOf(SanitizerKind::Memory | SanitizerKind::KernelMemory))
       Fn->addFnAttr(llvm::Attribute::SanitizeMemory);
   }
diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp
index 273f215ca94a8..86825a6ccf7a1 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -41,7 +41,8 @@ static const SanitizerMask NotAllowedWithExecuteOnly =
     SanitizerKind::Function | SanitizerKind::KCFI;
 static const SanitizerMask NeedsUnwindTables =
     SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Thread |
-    SanitizerKind::Memory | SanitizerKind::DataFlow;
+    SanitizerKind::Memory | SanitizerKind::DataFlow |
+    SanitizerKind::NumericalStability;
 static const SanitizerMask SupportsCoverage =
     SanitizerKind::Address | SanitizerKind::HWAddress |
     SanitizerKind::KernelAddress | SanitizerKind::KernelHWAddress |
@@ -53,7 +54,8 @@ static const SanitizerMask SupportsCoverage =
     SanitizerKind::DataFlow | SanitizerKind::Fuzzer |
     SanitizerKind::FuzzerNoLink | SanitizerKind::FloatDivideByZero |
     SanitizerKind::SafeStack | SanitizerKind::ShadowCallStack |
-    SanitizerKind::Thread | SanitizerKind::ObjCCast | SanitizerKind::KCFI;
+    SanitizerKind::Thread | SanitizerKind::ObjCCast | SanitizerKind::KCFI |
+    SanitizerKind::NumericalStability;
 static const SanitizerMask RecoverableByDefault =
     SanitizerKind::Undefined | SanitizerKind::Integer |
     SanitizerKind::ImplicitConversion | SanitizerKind::Nullability |
@@ -175,6 +177,7 @@ static void addDefaultIgnorelists(const Driver &D, SanitizerMask Kinds,
                      {"hwasan_ignorelist.txt", SanitizerKind::HWAddress},
                      {"memtag_ignorelist.txt", SanitizerKind::MemTag},
                      {"msan_ignorelist.txt", SanitizerKind::Memory},
+                     {"nsan_ignorelist.txt", SanitizerKind::NumericalStability},
                      {"tsan_ignorelist.txt", SanitizerKind::Thread},
                      {"dfsan_abilist.txt", SanitizerKind::DataFlow},
                      {"cfi_ignorelist.txt", SanitizerKind::CFI},
diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp
index db2c20d7b461d..3ecf57a94ea89 100644
--- a/clang/lib/Driver/ToolChains/Linux.cpp
+++ b/clang/lib/Driver/ToolChains/Linux.cpp
@@ -826,6 +826,10 @@ SanitizerMask Linux::getSupportedSanitizers() const {
   if (IsX86_64 || IsAArch64) {
     Res |= SanitizerKind::KernelHWAddress;
   }
+  if (IsX86_64) {
+    Res |= SanitizerKind::NumericalStability;
+  }
+
   // Work around "Cannot represent a difference across sections".
   if (getTriple().getArch() == llvm::Triple::ppc64)
     Res &= ~SanitizerKind::Function;
diff --git a/clang/test/CodeGen/sanitize-numerical-stability-attr.cpp b/clang/test/CodeGen/sanitize-numerical-stability-attr.cpp
new file mode 100644
index 0000000000000..56634c54962f4
--- /dev/null
+++ b/clang/test/CodeGen/sanitize-numerical-stability-attr.cpp
@@ -0,0 +1,49 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s | FileCheck -check-prefix=WITHOUT %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=numerical | FileCheck -check-prefix=NSAN %s
+// RUN: echo "src:%s" | sed -e 's/\\/\\\\/g' > %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=numerical -fsanitize-ignorelist=%t | FileCheck -check-prefix=BL %s
+
+// The sanitize_numerical_stability attribute should be attached to functions
+// when ThreadSanitizer is enabled, unless no_sanitize_numerical_stability attribute
+// is present.
+
+// WITHOUT:  NoNSAN1{{.*}}) [[NOATTR:#[0-9]+]]
+// BL:  NoNSAN1{{.*}}) [[NOATTR:#[0-9]+]]
+// NSAN:  NoNSAN1{{.*}}) [[NOATTR:#[0-9]+]]
+__attribute__((no_sanitize_numerical_stability))
+int NoNSAN1(int *a) { return *a; }
+
+// WITHOUT:  NoNSAN2{{.*}}) [[NOATTR]]
+// BL:  NoNSAN2{{.*}}) [[NOATTR]]
+// NSAN:  NoNSAN2{{.*}}) [[NOATTR]]
+__attribute__((no_sanitize_numerical_stability))
+int NoNSAN2(int *a);
+int NoNSAN2(int *a) { return *a; }
+
+// WITHOUT:  NoNSAN3{{.*}}) [[NOATTR:#[0-9]+]]
+// BL:  NoNSAN3{{.*}}) [[NOATTR:#[0-9]+]]
+// NSAN:  NoNSAN3{{.*}}) [[NOATTR:#[0-9]+]]
+__attribute__((no_sanitize("thread")))
+int NoNSAN3(int *a) { return *a; }
+
+// WITHOUT:  NSANOk{{.*}}) [[NOATTR]]
+// BL:  NSANOk{{.*}}) [[NOATTR]]
+// NSAN: NSANOk{{.*}}) [[WITH:#[0-9]+]]
+int NSANOk(int *a) { return *a; }
+
+// WITHOUT:  TemplateNSANOk{{.*}}) [[NOATTR]]
+// BL:  TemplateNSANOk{{.*}}) [[NOATTR]]
+// NSAN: TemplateNSANOk{{.*}}) [[WITH]]
+template<int i>
+int TemplateNSANOk() { return i; }
+
+// WITHOUT:  TemplateNoNSAN{{.*}}) [[NOATTR]]
+// BL:  TemplateNoNSAN{{.*}}) [[NOATTR]]
+// NSAN: TemplateNoNSAN{{.*}}) [[NOATTR]]
+template<int i>
+__attribute__((no_sanitize_numerical_stability))
+int TemplateNoNSAN() { return i; }
+
+int force_instance = TemplateNSANOk<42>()
+                   + TemplateNoNSAN<42>();
+
diff --git a/clang/test/Lexer/has_feature_numerical_stability_sanitizer.cpp b/clang/test/Lexer/has_feature_numerical_stability_sanitizer.cpp
new file mode 100644
index 0000000000000..78884977322b8
--- /dev/null
+++ b/clang/test/Lexer/has_feature_numerical_stability_sanitizer.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -E -fsanitize=numerical %s -o - | FileCheck --check-prefix=CHECK-NSAN %s
+// RUN: %clang_cc1 -E  %s -o - | FileCheck --check-prefix=CHECK-NO-NSAN %s
+
+#if __has_feature(numerical_stability_sanitizer)
+int NumericalStabilitySanitizerEnabled();
+#else
+int NumericalStabilitySanitizerDisabled();
+#endif
+
+// CHECK-NSAN: NumericalStabilitySanitizerEnabled
+// CHECK-NO-NSAN: NumericalStabilitySanitizerDisabled
diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td
index cef8b17769f0d..00ec7393c2265 100644
--- a/llvm/include/llvm/IR/Attributes.td
+++ b/llvm/include/llvm/IR/Attributes.td
@@ -285,6 +285,9 @@ def SanitizeHWAddress : EnumAttr<"sanitize_hwaddress", [FnAttr]>;
 /// MemTagSanitizer is on.
 def SanitizeMemTag : EnumAttr<"sanitize_memtag", [FnAttr]>;
 
+/// NumericalStabilitySanitizer is on.
+def SanitizeNumericalStability : EnumAttr<"sanitize_numericalstability", [FnAttr]>;
+
 /// Speculative Load Hardening is enabled.
 ///
 /// Note that this uses the default compatibility (always compatible during

@alexander-shaposhnikov alexander-shaposhnikov marked this pull request as draft May 30, 2024 08:32
@alexander-shaposhnikov alexander-shaposhnikov marked this pull request as ready for review May 30, 2024 09:10
@alexander-shaposhnikov alexander-shaposhnikov merged commit 48f8130 into llvm:main Jun 11, 2024
Lukacma pushed a commit to Lukacma/llvm-project that referenced this pull request Jun 12, 2024
Add plumbing for the numerical sanitizer on Clang's side.
@HerrCai0907 HerrCai0907 mentioned this pull request Jun 13, 2024
alexander-shaposhnikov added a commit that referenced this pull request Jun 18, 2024
This is a follow-up to #93783.
The current set of patches covers only x86_64,
therefore we should not enable this flag on arm64 yet.
AlexisPerry pushed a commit to llvm-project-tlp/llvm-project that referenced this pull request Jul 9, 2024
This is a follow-up to llvm#93783.
The current set of patches covers only x86_64,
therefore we should not enable this flag on arm64 yet.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:codegen IR generation bugs: mangling, exceptions, etc. clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category llvm:ir
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants