Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Clang][Sanitizers] Add numerical sanitizer #93783

Merged

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 llvm:ir labels May 30, 2024
@llvmbot
Copy link
Collaborator

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
Collaborator

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 merged commit 48f8130 into llvm:main Jun 11, 2024
4 of 6 checks passed
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 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