[llvm] 5bb6503 - Remove -bounds-checking-unique-traps (replace with -fno-sanitize-merge=local-bounds) (#120682)

via llvm-commits llvm-commits at lists.llvm.org
Fri Dec 20 10:07:49 PST 2024


Author: Thurston Dang
Date: 2024-12-20T10:07:44-08:00
New Revision: 5bb650345d83669434713146aaa431c1f7ad43d6

URL: https://github.com/llvm/llvm-project/commit/5bb650345d83669434713146aaa431c1f7ad43d6
DIFF: https://github.com/llvm/llvm-project/commit/5bb650345d83669434713146aaa431c1f7ad43d6.diff

LOG: Remove -bounds-checking-unique-traps (replace with -fno-sanitize-merge=local-bounds) (#120682)

#120613 removed -ubsan-unique-traps and replaced it with
-fno-sanitize-merge (introduced in #120511), which allows fine-grained
control of which UBSan checks to prevent merging. This analogous patch
removes -bound-checking-unique-traps, and allows it to be controlled via
-fno-sanitize-merge=local-bounds.

Most of this patch is simply plumbing through the compiler flags into
the bounds checking pass.

Note: this patch subtly changes -fsanitize-merge (the default) to also
include -fsanitize-merge=local-bounds. This is different from the
previous behavior, where -fsanitize-merge (or the old
-ubsan-unique-traps) did not affect local-bounds (requiring the separate
-bounds-checking-unique-traps). However, we argue that the new behavior
is more intuitive.

Removing -bounds-checking-unique-traps and merging its functionality
into -fsanitize-merge breaks backwards compatibility; we hope that this
is acceptable since '-mllvm -bounds-checking-unique-traps' was an
experimental flag.

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/docs/UndefinedBehaviorSanitizer.rst
    clang/lib/CodeGen/BackendUtil.cpp
    clang/test/CodeGen/bounds-checking.c
    llvm/include/llvm/Transforms/Instrumentation/BoundsChecking.h
    llvm/lib/Passes/PassBuilder.cpp
    llvm/lib/Passes/PassRegistry.def
    llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp
    llvm/test/Instrumentation/BoundsChecking/many-trap.ll
    llvm/test/Instrumentation/BoundsChecking/runtimes.ll
    llvm/test/Instrumentation/BoundsChecking/simple-32.ll
    llvm/test/Instrumentation/BoundsChecking/simple.ll
    llvm/test/Instrumentation/BoundsChecking/ubsan-unique-traps.ll

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 38c35aea3cf220..d9d016b30f93d6 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -445,10 +445,6 @@ New Compiler Flags
 - The ``-Warray-compare-cxx26`` warning has been added to warn about array comparison
   starting from C++26, this warning is enabled as an error by default.
 
-- '-fsanitize-merge' (default) and '-fno-sanitize-merge' have been added for
-  fine-grained control of which UBSan checks are allowed to be merged by the
-  backend (for example, -fno-sanitize-merge=bool,enum).
-
 Deprecated Compiler Flags
 -------------------------
 
@@ -488,8 +484,6 @@ Removed Compiler Flags
   derivatives) is now removed, since it's no longer possible to suppress the
   diagnostic (see above). Users can expect an `unknown warning` diagnostic if
   it's still in use.
-- The experimental flag '-ubsan-unique-traps' has been removed. It is
-  superseded by '-fno-sanitize-merge'.
 
 Attribute Changes in Clang
 --------------------------
@@ -1213,6 +1207,11 @@ Sanitizers
 
 - Implemented ``-f[no-]sanitize-trap=local-bounds``, and ``-f[no-]sanitize-recover=local-bounds``.
 
+- ``-fsanitize-merge`` (default) and ``-fno-sanitize-merge`` have been added for
+  fine-grained, unified control of which UBSan checks can potentially be merged
+  by the compiler (for example,
+  ``-fno-sanitize-merge=bool,enum,array-bounds,local-bounds``).
+
 Python Binding Changes
 ----------------------
 - Fixed an issue that led to crashes when calling ``Type.get_exception_specification_kind``.

diff  --git a/clang/docs/UndefinedBehaviorSanitizer.rst b/clang/docs/UndefinedBehaviorSanitizer.rst
index 671db7f9f36714..b9ee4484fb9aec 100644
--- a/clang/docs/UndefinedBehaviorSanitizer.rst
+++ b/clang/docs/UndefinedBehaviorSanitizer.rst
@@ -276,8 +276,8 @@ Stack traces and report symbolization
 If you want UBSan to print symbolized stack trace for each error report, you
 will need to:
 
-#. Compile with ``-g`` and ``-fno-omit-frame-pointer`` to get proper debug
-   information in your binary.
+#. Compile with ``-g``, ``-fno-sanitize-merge`` and ``-fno-omit-frame-pointer``
+   to get proper debug information in your binary.
 #. Run your program with environment variable
    ``UBSAN_OPTIONS=print_stacktrace=1``.
 #. Make sure ``llvm-symbolizer`` binary is in ``PATH``.

diff  --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index e6c9d77d29f6f1..04358cd6d7c232 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -1030,6 +1030,9 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
       PB.registerScalarOptimizerLateEPCallback(
           [this](FunctionPassManager &FPM, OptimizationLevel Level) {
             BoundsCheckingPass::ReportingMode Mode;
+            bool Merge = CodeGenOpts.SanitizeMergeHandlers.has(
+                SanitizerKind::LocalBounds);
+
             if (CodeGenOpts.SanitizeTrap.has(SanitizerKind::LocalBounds)) {
               Mode = BoundsCheckingPass::ReportingMode::Trap;
             } else if (CodeGenOpts.SanitizeMinimalRuntime) {
@@ -1041,7 +1044,8 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
                          ? BoundsCheckingPass::ReportingMode::FullRuntime
                          : BoundsCheckingPass::ReportingMode::FullRuntimeAbort;
             }
-            FPM.addPass(BoundsCheckingPass(Mode));
+            BoundsCheckingPass::BoundsCheckingOptions Options(Mode, Merge);
+            FPM.addPass(BoundsCheckingPass(Options));
           });
 
     // Don't add sanitizers if we are here from ThinLTO PostLink. That already

diff  --git a/clang/test/CodeGen/bounds-checking.c b/clang/test/CodeGen/bounds-checking.c
index f9319ca61670c3..5e6b317a99969e 100644
--- a/clang/test/CodeGen/bounds-checking.c
+++ b/clang/test/CodeGen/bounds-checking.c
@@ -1,12 +1,14 @@
-// RUN: %clang_cc1 -fsanitize=local-bounds    -fsanitize-trap=local-bounds -emit-llvm -triple x86_64-apple-darwin10              %s -o - |     FileCheck %s
-// RUN: %clang_cc1 -fsanitize=array-bounds -O                              -emit-llvm -triple x86_64-apple-darwin10 %s -o -              | not FileCheck %s
+// N.B. The clang driver defaults to -fsanitize-merge but clang_cc1 effectively
+// defaults to -fno-sanitize-merge.
 // RUN: %clang_cc1 -fsanitize=array-bounds -O -fsanitize-trap=array-bounds -emit-llvm -triple x86_64-apple-darwin10 -DNO_DYNAMIC %s -o - |     FileCheck %s
+// RUN: %clang_cc1 -fsanitize=array-bounds -O                              -emit-llvm -triple x86_64-apple-darwin10 %s -o -              | not FileCheck %s
 //
-// RUN: %clang_cc1 -fsanitize=local-bounds -fsanitize-trap=local-bounds -O3 -mllvm -bounds-checking-unique-traps -emit-llvm -triple x86_64-apple-darwin10 %s -o - |     FileCheck %s --check-prefixes=NOOPTLOCAL
-// RUN: %clang_cc1 -fsanitize=local-bounds -fsanitize-trap=local-bounds -O3                                      -emit-llvm -triple x86_64-apple-darwin10 %s -o - | not FileCheck %s --check-prefixes=NOOPTLOCAL
+// RUN: %clang_cc1 -fsanitize=local-bounds    -fsanitize-trap=local-bounds -emit-llvm -triple x86_64-apple-darwin10              %s -o - |     FileCheck %s
+//
+// RUN: %clang_cc1 -fsanitize=local-bounds -fsanitize-trap=local-bounds                               -O3 -emit-llvm -triple x86_64-apple-darwin10 %s -o - |     FileCheck %s --check-prefixes=NOOPTLOCAL
+// RUN: %clang_cc1 -fsanitize=local-bounds -fsanitize-trap=local-bounds -fno-sanitize-merge           -O3 -emit-llvm -triple x86_64-apple-darwin10 %s -o - |     FileCheck %s --check-prefixes=NOOPTLOCAL
+// RUN: %clang_cc1 -fsanitize=local-bounds -fsanitize-trap=local-bounds -fsanitize-merge=local-bounds -O3 -emit-llvm -triple x86_64-apple-darwin10 %s -o - | not FileCheck %s --check-prefixes=NOOPTLOCAL
 //
-// N.B. The clang driver defaults to -fsanitize-merge but clang_cc1 effectively
-// defaults to -fno-sanitize-merge.
 // RUN: %clang_cc1 -fsanitize=array-bounds -fsanitize-trap=array-bounds                               -O3 -emit-llvm -triple x86_64-apple-darwin10 %s -o - |     FileCheck %s --check-prefixes=NOOPTARRAY
 // RUN: %clang_cc1 -fsanitize=array-bounds -fsanitize-trap=array-bounds -fno-sanitize-merge           -O3 -emit-llvm -triple x86_64-apple-darwin10 %s -o - |     FileCheck %s --check-prefixes=NOOPTARRAY
 // RUN: %clang_cc1 -fsanitize=array-bounds -fsanitize-trap=array-bounds -fsanitize-merge=array-bounds -O3 -emit-llvm -triple x86_64-apple-darwin10 %s -o - | not FileCheck %s --check-prefixes=NOOPTARRAY

diff  --git a/llvm/include/llvm/Transforms/Instrumentation/BoundsChecking.h b/llvm/include/llvm/Transforms/Instrumentation/BoundsChecking.h
index 1876e5b72e8c99..ee71aa64f85eed 100644
--- a/llvm/include/llvm/Transforms/Instrumentation/BoundsChecking.h
+++ b/llvm/include/llvm/Transforms/Instrumentation/BoundsChecking.h
@@ -17,6 +17,7 @@ class Function;
 /// A pass to instrument code and perform run-time bounds checking on loads,
 /// stores, and other memory intrinsics.
 class BoundsCheckingPass : public PassInfoMixin<BoundsCheckingPass> {
+
 public:
   enum class ReportingMode {
     Trap,
@@ -26,15 +27,21 @@ class BoundsCheckingPass : public PassInfoMixin<BoundsCheckingPass> {
     FullRuntimeAbort,
   };
 
-private:
-  ReportingMode Mode = ReportingMode::Trap;
+  struct BoundsCheckingOptions {
+    BoundsCheckingOptions(ReportingMode Mode, bool Merge);
 
-public:
-  BoundsCheckingPass(ReportingMode Mode) : Mode(Mode) {}
+    ReportingMode Mode;
+    bool Merge;
+  };
+
+  BoundsCheckingPass(BoundsCheckingOptions Options) : Options(Options) {}
   PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
   static bool isRequired() { return true; }
   void printPipeline(raw_ostream &OS,
                      function_ref<StringRef(StringRef)> MapClassName2PassName);
+
+private:
+  BoundsCheckingOptions Options;
 };
 
 } // end namespace llvm

diff  --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index d70ac48f251180..a936f5381137c6 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -1281,23 +1281,25 @@ parseRegAllocFastPassOptions(PassBuilder &PB, StringRef Params) {
   return Opts;
 }
 
-Expected<BoundsCheckingPass::ReportingMode>
+Expected<BoundsCheckingPass::BoundsCheckingOptions>
 parseBoundsCheckingOptions(StringRef Params) {
-  BoundsCheckingPass::ReportingMode Mode =
-      BoundsCheckingPass::ReportingMode::Trap;
+  BoundsCheckingPass::BoundsCheckingOptions Options(
+      BoundsCheckingPass::ReportingMode::Trap, false);
   while (!Params.empty()) {
     StringRef ParamName;
     std::tie(ParamName, Params) = Params.split(';');
     if (ParamName == "trap") {
-      Mode = BoundsCheckingPass::ReportingMode::Trap;
+      Options.Mode = BoundsCheckingPass::ReportingMode::Trap;
     } else if (ParamName == "rt") {
-      Mode = BoundsCheckingPass::ReportingMode::FullRuntime;
+      Options.Mode = BoundsCheckingPass::ReportingMode::FullRuntime;
     } else if (ParamName == "rt-abort") {
-      Mode = BoundsCheckingPass::ReportingMode::FullRuntimeAbort;
+      Options.Mode = BoundsCheckingPass::ReportingMode::FullRuntimeAbort;
     } else if (ParamName == "min-rt") {
-      Mode = BoundsCheckingPass::ReportingMode::MinRuntime;
+      Options.Mode = BoundsCheckingPass::ReportingMode::MinRuntime;
     } else if (ParamName == "min-rt-abort") {
-      Mode = BoundsCheckingPass::ReportingMode::MinRuntimeAbort;
+      Options.Mode = BoundsCheckingPass::ReportingMode::MinRuntimeAbort;
+    } else if (ParamName == "merge") {
+      Options.Merge = true;
     } else {
       return make_error<StringError>(
           formatv("invalid BoundsChecking pass parameter '{0}' ", ParamName)
@@ -1305,7 +1307,7 @@ parseBoundsCheckingOptions(StringRef Params) {
           inconvertibleErrorCode());
     }
   }
-  return Mode;
+  return Options;
 }
 
 } // namespace

diff  --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index ba3adcb0e317c0..9f0b09278edcca 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -624,8 +624,8 @@ FUNCTION_PASS_WITH_PARAMS(
     parseWinEHPrepareOptions, "demote-catchswitch-only")
 FUNCTION_PASS_WITH_PARAMS(
     "bounds-checking", "BoundsCheckingPass",
-    [](BoundsCheckingPass::ReportingMode Mode) {
-      return BoundsCheckingPass(Mode);
+    [](BoundsCheckingPass::BoundsCheckingOptions Options) {
+      return BoundsCheckingPass(Options);
     },
     parseBoundsCheckingOptions, "trap")
 #undef FUNCTION_PASS_WITH_PARAMS

diff  --git a/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp b/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp
index f639d0628d6053..41e50385812460 100644
--- a/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp
+++ b/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp
@@ -37,15 +37,16 @@ using namespace llvm;
 static cl::opt<bool> SingleTrapBB("bounds-checking-single-trap",
                                   cl::desc("Use one trap block per function"));
 
-static cl::opt<bool> DebugTrapBB("bounds-checking-unique-traps",
-                                 cl::desc("Always use one trap per check"));
-
 STATISTIC(ChecksAdded, "Bounds checks added");
 STATISTIC(ChecksSkipped, "Bounds checks skipped");
 STATISTIC(ChecksUnable, "Bounds checks unable to add");
 
 using BuilderTy = IRBuilder<TargetFolder>;
 
+BoundsCheckingPass::BoundsCheckingOptions::BoundsCheckingOptions(
+    ReportingMode Mode, bool Merge)
+    : Mode(Mode), Merge(Merge) {}
+
 /// Gets the conditions under which memory accessing instructions will overflow.
 ///
 /// \p Ptr is the pointer that will be read/written, and \p InstVal is either
@@ -105,7 +106,7 @@ static Value *getBoundsCheckCond(Value *Ptr, Value *InstVal,
   return Or;
 }
 
-static CallInst *InsertTrap(BuilderTy &IRB) {
+static CallInst *InsertTrap(BuilderTy &IRB, bool DebugTrapBB) {
   if (!DebugTrapBB)
     return IRB.CreateIntrinsic(Intrinsic::trap, {}, {});
   // FIXME: Ideally we would use the SanitizerHandler::OutOfBounds constant.
@@ -169,9 +170,10 @@ struct ReportingOpts {
   bool MayReturn = false;
   bool UseTrap = false;
   bool MinRuntime = false;
+  bool MayMerge = true;
   StringRef Name;
 
-  ReportingOpts(BoundsCheckingPass::ReportingMode Mode) {
+  ReportingOpts(BoundsCheckingPass::ReportingMode Mode, bool Merge) {
     switch (Mode) {
     case BoundsCheckingPass::ReportingMode::Trap:
       UseTrap = true;
@@ -193,6 +195,8 @@ struct ReportingOpts {
       Name = "__ubsan_handle_local_out_of_bounds_abort";
       break;
     }
+
+    MayMerge = Merge;
   }
 };
 
@@ -253,13 +257,12 @@ static bool addBoundsChecking(Function &F, TargetLibraryInfo &TLI,
     BasicBlock *TrapBB = BasicBlock::Create(Fn->getContext(), "trap", Fn);
     IRB.SetInsertPoint(TrapBB);
 
+    bool DebugTrapBB = !Opts.MayMerge;
     CallInst *TrapCall = Opts.UseTrap
-                             ? InsertTrap(IRB)
+                             ? InsertTrap(IRB, DebugTrapBB)
                              : InsertCall(IRB, Opts.MayReturn, Opts.Name);
-    if (DebugTrapBB) {
-      // FIXME: Pass option form clang.
+    if (DebugTrapBB)
       TrapCall->addFnAttr(llvm::Attribute::NoMerge);
-    }
 
     TrapCall->setDoesNotThrow();
     TrapCall->setDebugLoc(DebugLoc);
@@ -289,7 +292,8 @@ PreservedAnalyses BoundsCheckingPass::run(Function &F, FunctionAnalysisManager &
   auto &TLI = AM.getResult<TargetLibraryAnalysis>(F);
   auto &SE = AM.getResult<ScalarEvolutionAnalysis>(F);
 
-  if (!addBoundsChecking(F, TLI, SE, ReportingOpts(Mode)))
+  if (!addBoundsChecking(F, TLI, SE,
+                         ReportingOpts(Options.Mode, Options.Merge)))
     return PreservedAnalyses::all();
 
   return PreservedAnalyses::none();
@@ -299,21 +303,24 @@ void BoundsCheckingPass::printPipeline(
     raw_ostream &OS, function_ref<StringRef(StringRef)> MapClassName2PassName) {
   static_cast<PassInfoMixin<BoundsCheckingPass> *>(this)->printPipeline(
       OS, MapClassName2PassName);
-  switch (Mode) {
+  switch (Options.Mode) {
   case ReportingMode::Trap:
-    OS << "<trap>";
+    OS << "<trap";
     break;
   case ReportingMode::MinRuntime:
-    OS << "<min-rt>";
+    OS << "<min-rt";
     break;
   case ReportingMode::MinRuntimeAbort:
-    OS << "<min-rt-abort>";
+    OS << "<min-rt-abort";
     break;
   case ReportingMode::FullRuntime:
-    OS << "<rt>";
+    OS << "<rt";
     break;
   case ReportingMode::FullRuntimeAbort:
-    OS << "<rt-abort>";
+    OS << "<rt-abort";
     break;
   }
+  if (Options.Merge)
+    OS << ";merge";
+  OS << ">";
 }

diff  --git a/llvm/test/Instrumentation/BoundsChecking/many-trap.ll b/llvm/test/Instrumentation/BoundsChecking/many-trap.ll
index e9cde95cd09e59..4e157520dbafe3 100644
--- a/llvm/test/Instrumentation/BoundsChecking/many-trap.ll
+++ b/llvm/test/Instrumentation/BoundsChecking/many-trap.ll
@@ -1,5 +1,5 @@
-; RUN: opt < %s -passes=bounds-checking -S | FileCheck %s
-; RUN: opt < %s -passes=bounds-checking -bounds-checking-single-trap -S | FileCheck -check-prefix=SINGLE %s
+; RUN: opt < %s -passes='bounds-checking<merge>' -S | FileCheck %s
+; RUN: opt < %s -passes='bounds-checking<merge>' -bounds-checking-single-trap -S | FileCheck -check-prefix=SINGLE %s
 target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
 
 ; CHECK: @f1

diff  --git a/llvm/test/Instrumentation/BoundsChecking/runtimes.ll b/llvm/test/Instrumentation/BoundsChecking/runtimes.ll
index 357f92aca85c08..7b95a4092af77e 100644
--- a/llvm/test/Instrumentation/BoundsChecking/runtimes.ll
+++ b/llvm/test/Instrumentation/BoundsChecking/runtimes.ll
@@ -1,10 +1,13 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
-; RUN: opt < %s -passes=bounds-checking                 -S | FileCheck %s --check-prefixes=TR
-; RUN: opt < %s -passes='bounds-checking<trap>'         -S | FileCheck %s --check-prefixes=TR
-; RUN: opt < %s -passes='bounds-checking<rt>'           -S | FileCheck %s --check-prefixes=RT
-; RUN: opt < %s -passes='bounds-checking<rt-abort>'     -S | FileCheck %s --check-prefixes=RTABORT
-; RUN: opt < %s -passes='bounds-checking<min-rt>'       -S | FileCheck %s --check-prefixes=MINRT
-; RUN: opt < %s -passes='bounds-checking<min-rt-abort>' -S | FileCheck %s --check-prefixes=MINRTABORT
+; RUN: opt < %s -passes=bounds-checking                 -S | FileCheck %s --check-prefixes=TR-NOMERGE
+; RUN: opt < %s -passes='bounds-checking<trap>'         -S | FileCheck %s --check-prefixes=TR-NOMERGE
+; RUN: opt < %s -passes='bounds-checking<rt>'           -S | FileCheck %s --check-prefixes=RT-NOMERGE
+; RUN: opt < %s -passes='bounds-checking<rt-abort>'     -S | FileCheck %s --check-prefixes=RTABORT-NOMERGE
+; RUN: opt < %s -passes='bounds-checking<min-rt>'       -S | FileCheck %s --check-prefixes=MINRT-NOMERGE
+; RUN: opt < %s -passes='bounds-checking<min-rt-abort>' -S | FileCheck %s --check-prefixes=MINRTABORT-NOMERGE
+;
+; RUN: opt < %s -passes='bounds-checking<trap;merge>'   -S | FileCheck %s --check-prefixes=TR
+; RUN: opt < %s -passes='bounds-checking<rt;merge>'     -S | FileCheck %s --check-prefixes=RT
 
 target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
 
@@ -41,55 +44,96 @@ define void @f1(i64 %x) nounwind {
 ; RT-NEXT:    call void @__ubsan_handle_local_out_of_bounds() #[[ATTR0]]
 ; RT-NEXT:    br label %[[BB7]]
 ;
-; RTABORT-LABEL: define void @f1(
-; RTABORT-SAME: i64 [[X:%.*]]) #[[ATTR0:[0-9]+]] {
-; RTABORT-NEXT:    [[TMP1:%.*]] = mul i64 16, [[X]]
-; RTABORT-NEXT:    [[TMP2:%.*]] = alloca i128, i64 [[X]], align 8
-; RTABORT-NEXT:    [[TMP3:%.*]] = sub i64 [[TMP1]], 0
-; RTABORT-NEXT:    [[TMP4:%.*]] = icmp ult i64 [[TMP3]], 16
-; RTABORT-NEXT:    [[TMP5:%.*]] = or i1 false, [[TMP4]]
-; RTABORT-NEXT:    [[TMP6:%.*]] = or i1 false, [[TMP5]]
-; RTABORT-NEXT:    br i1 [[TMP6]], label %[[TRAP:.*]], label %[[BB7:.*]]
-; RTABORT:       [[BB7]]:
-; RTABORT-NEXT:    [[TMP8:%.*]] = load i128, ptr [[TMP2]], align 4
-; RTABORT-NEXT:    ret void
-; RTABORT:       [[TRAP]]:
-; RTABORT-NEXT:    call void @__ubsan_handle_local_out_of_bounds_abort() #[[ATTR1:[0-9]+]]
-; RTABORT-NEXT:    unreachable
+; TR-NOMERGE-LABEL: define void @f1(
+; TR-NOMERGE-SAME: i64 [[X:%.*]]) #[[ATTR0:[0-9]+]] {
+; TR-NOMERGE-NEXT:    [[TMP1:%.*]] = mul i64 16, [[X]]
+; TR-NOMERGE-NEXT:    [[TMP2:%.*]] = alloca i128, i64 [[X]], align 8
+; TR-NOMERGE-NEXT:    [[TMP3:%.*]] = sub i64 [[TMP1]], 0
+; TR-NOMERGE-NEXT:    [[TMP4:%.*]] = icmp ult i64 [[TMP3]], 16
+; TR-NOMERGE-NEXT:    [[TMP5:%.*]] = or i1 false, [[TMP4]]
+; TR-NOMERGE-NEXT:    [[TMP6:%.*]] = or i1 false, [[TMP5]]
+; TR-NOMERGE-NEXT:    br i1 [[TMP6]], label %[[TRAP:.*]], label %[[BB7:.*]]
+; TR-NOMERGE:       [[BB7]]:
+; TR-NOMERGE-NEXT:    [[TMP8:%.*]] = load i128, ptr [[TMP2]], align 4
+; TR-NOMERGE-NEXT:    ret void
+; TR-NOMERGE:       [[TRAP]]:
+; TR-NOMERGE-NEXT:    call void @llvm.ubsantrap(i8 3) #[[ATTR2:[0-9]+]]
+; TR-NOMERGE-NEXT:    unreachable
+;
+; RT-NOMERGE-LABEL: define void @f1(
+; RT-NOMERGE-SAME: i64 [[X:%.*]]) #[[ATTR0:[0-9]+]] {
+; RT-NOMERGE-NEXT:    [[TMP1:%.*]] = mul i64 16, [[X]]
+; RT-NOMERGE-NEXT:    [[TMP2:%.*]] = alloca i128, i64 [[X]], align 8
+; RT-NOMERGE-NEXT:    [[TMP3:%.*]] = sub i64 [[TMP1]], 0
+; RT-NOMERGE-NEXT:    [[TMP4:%.*]] = icmp ult i64 [[TMP3]], 16
+; RT-NOMERGE-NEXT:    [[TMP5:%.*]] = or i1 false, [[TMP4]]
+; RT-NOMERGE-NEXT:    [[TMP6:%.*]] = or i1 false, [[TMP5]]
+; RT-NOMERGE-NEXT:    br i1 [[TMP6]], label %[[TRAP:.*]], label %[[BB7:.*]]
+; RT-NOMERGE:       [[BB7]]:
+; RT-NOMERGE-NEXT:    [[TMP8:%.*]] = load i128, ptr [[TMP2]], align 4
+; RT-NOMERGE-NEXT:    ret void
+; RT-NOMERGE:       [[TRAP]]:
+; RT-NOMERGE-NEXT:    call void @__ubsan_handle_local_out_of_bounds() #[[ATTR1:[0-9]+]]
+; RT-NOMERGE-NEXT:    br label %[[BB7]]
+;
+; RTABORT-NOMERGE-LABEL: define void @f1(
+; RTABORT-NOMERGE-SAME: i64 [[X:%.*]]) #[[ATTR0:[0-9]+]] {
+; RTABORT-NOMERGE-NEXT:    [[TMP1:%.*]] = mul i64 16, [[X]]
+; RTABORT-NOMERGE-NEXT:    [[TMP2:%.*]] = alloca i128, i64 [[X]], align 8
+; RTABORT-NOMERGE-NEXT:    [[TMP3:%.*]] = sub i64 [[TMP1]], 0
+; RTABORT-NOMERGE-NEXT:    [[TMP4:%.*]] = icmp ult i64 [[TMP3]], 16
+; RTABORT-NOMERGE-NEXT:    [[TMP5:%.*]] = or i1 false, [[TMP4]]
+; RTABORT-NOMERGE-NEXT:    [[TMP6:%.*]] = or i1 false, [[TMP5]]
+; RTABORT-NOMERGE-NEXT:    br i1 [[TMP6]], label %[[TRAP:.*]], label %[[BB7:.*]]
+; RTABORT-NOMERGE:       [[BB7]]:
+; RTABORT-NOMERGE-NEXT:    [[TMP8:%.*]] = load i128, ptr [[TMP2]], align 4
+; RTABORT-NOMERGE-NEXT:    ret void
+; RTABORT-NOMERGE:       [[TRAP]]:
+; RTABORT-NOMERGE-NEXT:    call void @__ubsan_handle_local_out_of_bounds_abort() #[[ATTR2:[0-9]+]]
+; RTABORT-NOMERGE-NEXT:    unreachable
 ;
-; MINRT-LABEL: define void @f1(
-; MINRT-SAME: i64 [[X:%.*]]) #[[ATTR0:[0-9]+]] {
-; MINRT-NEXT:    [[TMP1:%.*]] = mul i64 16, [[X]]
-; MINRT-NEXT:    [[TMP2:%.*]] = alloca i128, i64 [[X]], align 8
-; MINRT-NEXT:    [[TMP3:%.*]] = sub i64 [[TMP1]], 0
-; MINRT-NEXT:    [[TMP4:%.*]] = icmp ult i64 [[TMP3]], 16
-; MINRT-NEXT:    [[TMP5:%.*]] = or i1 false, [[TMP4]]
-; MINRT-NEXT:    [[TMP6:%.*]] = or i1 false, [[TMP5]]
-; MINRT-NEXT:    br i1 [[TMP6]], label %[[TRAP:.*]], label %[[BB7:.*]]
-; MINRT:       [[BB7]]:
-; MINRT-NEXT:    [[TMP8:%.*]] = load i128, ptr [[TMP2]], align 4
-; MINRT-NEXT:    ret void
-; MINRT:       [[TRAP]]:
-; MINRT-NEXT:    call void @__ubsan_handle_local_out_of_bounds_minimal() #[[ATTR0]]
-; MINRT-NEXT:    br label %[[BB7]]
+; MINRT-NOMERGE-LABEL: define void @f1(
+; MINRT-NOMERGE-SAME: i64 [[X:%.*]]) #[[ATTR0:[0-9]+]] {
+; MINRT-NOMERGE-NEXT:    [[TMP1:%.*]] = mul i64 16, [[X]]
+; MINRT-NOMERGE-NEXT:    [[TMP2:%.*]] = alloca i128, i64 [[X]], align 8
+; MINRT-NOMERGE-NEXT:    [[TMP3:%.*]] = sub i64 [[TMP1]], 0
+; MINRT-NOMERGE-NEXT:    [[TMP4:%.*]] = icmp ult i64 [[TMP3]], 16
+; MINRT-NOMERGE-NEXT:    [[TMP5:%.*]] = or i1 false, [[TMP4]]
+; MINRT-NOMERGE-NEXT:    [[TMP6:%.*]] = or i1 false, [[TMP5]]
+; MINRT-NOMERGE-NEXT:    br i1 [[TMP6]], label %[[TRAP:.*]], label %[[BB7:.*]]
+; MINRT-NOMERGE:       [[BB7]]:
+; MINRT-NOMERGE-NEXT:    [[TMP8:%.*]] = load i128, ptr [[TMP2]], align 4
+; MINRT-NOMERGE-NEXT:    ret void
+; MINRT-NOMERGE:       [[TRAP]]:
+; MINRT-NOMERGE-NEXT:    call void @__ubsan_handle_local_out_of_bounds_minimal() #[[ATTR1:[0-9]+]]
+; MINRT-NOMERGE-NEXT:    br label %[[BB7]]
 ;
-; MINRTABORT-LABEL: define void @f1(
-; MINRTABORT-SAME: i64 [[X:%.*]]) #[[ATTR0:[0-9]+]] {
-; MINRTABORT-NEXT:    [[TMP1:%.*]] = mul i64 16, [[X]]
-; MINRTABORT-NEXT:    [[TMP2:%.*]] = alloca i128, i64 [[X]], align 8
-; MINRTABORT-NEXT:    [[TMP3:%.*]] = sub i64 [[TMP1]], 0
-; MINRTABORT-NEXT:    [[TMP4:%.*]] = icmp ult i64 [[TMP3]], 16
-; MINRTABORT-NEXT:    [[TMP5:%.*]] = or i1 false, [[TMP4]]
-; MINRTABORT-NEXT:    [[TMP6:%.*]] = or i1 false, [[TMP5]]
-; MINRTABORT-NEXT:    br i1 [[TMP6]], label %[[TRAP:.*]], label %[[BB7:.*]]
-; MINRTABORT:       [[BB7]]:
-; MINRTABORT-NEXT:    [[TMP8:%.*]] = load i128, ptr [[TMP2]], align 4
-; MINRTABORT-NEXT:    ret void
-; MINRTABORT:       [[TRAP]]:
-; MINRTABORT-NEXT:    call void @__ubsan_handle_local_out_of_bounds_minimal_abort() #[[ATTR1:[0-9]+]]
-; MINRTABORT-NEXT:    unreachable
+; MINRTABORT-NOMERGE-LABEL: define void @f1(
+; MINRTABORT-NOMERGE-SAME: i64 [[X:%.*]]) #[[ATTR0:[0-9]+]] {
+; MINRTABORT-NOMERGE-NEXT:    [[TMP1:%.*]] = mul i64 16, [[X]]
+; MINRTABORT-NOMERGE-NEXT:    [[TMP2:%.*]] = alloca i128, i64 [[X]], align 8
+; MINRTABORT-NOMERGE-NEXT:    [[TMP3:%.*]] = sub i64 [[TMP1]], 0
+; MINRTABORT-NOMERGE-NEXT:    [[TMP4:%.*]] = icmp ult i64 [[TMP3]], 16
+; MINRTABORT-NOMERGE-NEXT:    [[TMP5:%.*]] = or i1 false, [[TMP4]]
+; MINRTABORT-NOMERGE-NEXT:    [[TMP6:%.*]] = or i1 false, [[TMP5]]
+; MINRTABORT-NOMERGE-NEXT:    br i1 [[TMP6]], label %[[TRAP:.*]], label %[[BB7:.*]]
+; MINRTABORT-NOMERGE:       [[BB7]]:
+; MINRTABORT-NOMERGE-NEXT:    [[TMP8:%.*]] = load i128, ptr [[TMP2]], align 4
+; MINRTABORT-NOMERGE-NEXT:    ret void
+; MINRTABORT-NOMERGE:       [[TRAP]]:
+; MINRTABORT-NOMERGE-NEXT:    call void @__ubsan_handle_local_out_of_bounds_minimal_abort() #[[ATTR2:[0-9]+]]
+; MINRTABORT-NOMERGE-NEXT:    unreachable
 ;
   %1 = alloca i128, i64 %x
   %3 = load i128, ptr %1, align 4
   ret void
 }
+
+; TR-NOMERGE: attributes #[[ATTR2]] = { nomerge noreturn nounwind }
+; RT-NOMERGE: attributes #[[ATTR1]] = { nomerge nounwind }
+; RTABORT-NOMERGE: attributes #[[ATTR2]] = { nomerge noreturn nounwind }
+; MINRT-NOMERGE: attributes #[[ATTR1]] = { nomerge nounwind }
+; MINRTABORT-NOMERGE: attributes #[[ATTR2]] = { nomerge noreturn nounwind }
+;
+; TR: attributes #[[ATTR2]] = { noreturn nounwind }
+; RT: attributes #[[ATTR0]] = { nounwind }

diff  --git a/llvm/test/Instrumentation/BoundsChecking/simple-32.ll b/llvm/test/Instrumentation/BoundsChecking/simple-32.ll
index b707adaca434ca..6f8d373d4c5966 100644
--- a/llvm/test/Instrumentation/BoundsChecking/simple-32.ll
+++ b/llvm/test/Instrumentation/BoundsChecking/simple-32.ll
@@ -1,4 +1,4 @@
-; RUN: opt < %s -passes=bounds-checking -S | FileCheck %s
+; RUN: opt < %s -passes='bounds-checking<merge>' -S | FileCheck %s
 
 target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S128"
 

diff  --git a/llvm/test/Instrumentation/BoundsChecking/simple.ll b/llvm/test/Instrumentation/BoundsChecking/simple.ll
index 914cafdc57f9d3..ce2540cf49cccc 100644
--- a/llvm/test/Instrumentation/BoundsChecking/simple.ll
+++ b/llvm/test/Instrumentation/BoundsChecking/simple.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=bounds-checking -S | FileCheck %s
+; RUN: opt < %s -passes='bounds-checking<merge>' -S | FileCheck %s
 target datalayout = "e-p:64:64:64-p1:16:16:16-p2:64:64:64:48-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
 
 @.str = private constant [8 x i8] c"abcdefg\00"

diff  --git a/llvm/test/Instrumentation/BoundsChecking/ubsan-unique-traps.ll b/llvm/test/Instrumentation/BoundsChecking/ubsan-unique-traps.ll
index a3f34007e9b09f..5fdb9c78357e73 100644
--- a/llvm/test/Instrumentation/BoundsChecking/ubsan-unique-traps.ll
+++ b/llvm/test/Instrumentation/BoundsChecking/ubsan-unique-traps.ll
@@ -1,5 +1,7 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=bounds-checking -bounds-checking-unique-traps -S | FileCheck %s
+; RUN: opt < %s -passes=bounds-checking          -S | FileCheck %s
+; RUN: opt < %s -passes='bounds-checking<merge>' -S | not FileCheck %s
+
 target datalayout = "e-p:64:64:64-p1:16:16:16-p2:64:64:64:48-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
 
 declare noalias ptr @malloc(i64) nounwind allocsize(0)


        


More information about the llvm-commits mailing list