Skip to content

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

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

Merged
merged 5 commits into from
Dec 20, 2024

Conversation

thurstond
Copy link
Contributor

@thurstond thurstond commented Dec 20, 2024

#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.

…e=local-bounds)

-fno-sanitize-merge (introduced in llvm#120511) combines the functionality of -ubsan-unique-traps
and -bounds-checking-unique-traps, while allowing fine-grained control
of which UBSan checks to prevent merging. llvm#120613 removed -ubsan-unique-traps.
This patch removes -bound-checking-unique-traps, which can be controlled
via -fno-sanitize-merge=local-bounds.

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.
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:codegen IR generation bugs: mangling, exceptions, etc. llvm:transforms labels Dec 20, 2024
@llvmbot
Copy link
Member

llvmbot commented Dec 20, 2024

@llvm/pr-subscribers-clang-codegen
@llvm/pr-subscribers-llvm-transforms

@llvm/pr-subscribers-clang

Author: Thurston Dang (thurstond)

Changes

-fno-sanitize-merge (introduced in #120511) combines the functionality of -ubsan-unique-traps and -bounds-checking-unique-traps, while allowing fine-grained control of which UBSan checks to prevent merging. #120613 removed -ubsan-unique-traps. This patch removes -bound-checking-unique-traps, which can 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.


Patch is 21.68 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/120682.diff

9 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+9-5)
  • (modified) clang/lib/CodeGen/BackendUtil.cpp (+4-1)
  • (modified) clang/test/CodeGen/bounds-checking.c (+8-6)
  • (modified) llvm/include/llvm/Transforms/Instrumentation/BoundsChecking.h (+11-4)
  • (modified) llvm/lib/Passes/PassBuilder.cpp (+20-9)
  • (modified) llvm/lib/Passes/PassRegistry.def (+2-2)
  • (modified) llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp (+13-11)
  • (modified) llvm/test/Instrumentation/BoundsChecking/runtimes.ll (+107)
  • (modified) llvm/test/Instrumentation/BoundsChecking/ubsan-unique-traps.ll (+4-1)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index b8d92a6c881c68..0c6c894e17416a 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -445,9 +445,10 @@ 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).
+- ``-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``).
 
 Deprecated Compiler Flags
 -------------------------
@@ -488,8 +489,11 @@ 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'.
+- The experimental flags '-ubsan-unique-traps' and
+  '-bounds-checking-unique-traps' have been removed. The combination of the
+  two flags is equivalent to '-fno-sanitize-merge' with no parameters.
+  '-bounds-checking-unique-traps' can be selectively controlled via
+  '-f(no-)sanitize-merge=local-bounds'.
 
 Attribute Changes in Clang
 --------------------------
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index e6c9d77d29f6f1..bfb73aa51b9b5b 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -1030,6 +1030,8 @@ 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 +1043,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..eca93d89838134 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..87756acf724261 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -1281,23 +1281,34 @@ 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, true);
   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.consume_front("merge=")) {
+      if (ParamName == "true")
+        Options.Merge = true;
+      else if (ParamName == "false")
+        Options.Merge = false;
+      else {
+        return make_error<StringError>(
+            formatv("invalid BoundsChecking pass merge parameter: '{0}' ",
+                    ParamName)
+                .str(),
+            inconvertibleErrorCode());
+      }
     } else {
       return make_error<StringError>(
           formatv("invalid BoundsChecking pass parameter '{0}' ", ParamName)
@@ -1305,7 +1316,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..5ce3e0de59c559 100644
--- a/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp
+++ b/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp
@@ -37,15 +37,15 @@ 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 +105,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 +169,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 +194,8 @@ struct ReportingOpts {
       Name = "__ubsan_handle_local_out_of_bounds_abort";
       break;
     }
+
+    MayMerge = Merge;
   }
 };
 
@@ -253,13 +256,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 +291,7 @@ 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,7 +301,7 @@ 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>";
     break;
diff --git a/llvm/test/Instrumentation/BoundsChecking/runtimes.ll b/llvm/test/Instrumentation/BoundsChecking/runtimes.ll
index 357f92aca85c08..8726606665d7ca 100644
--- a/llvm/test/Instrumentation/BoundsChecking/runtimes.ll
+++ b/llvm/test/Instrumentation/BoundsChecking/runtimes.ll
@@ -5,6 +5,21 @@
 ; 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
+;
+; merge defaults to true
+; RUN: opt < %s -passes='bounds-checking<merge=true>'              -S | FileCheck %s --check-prefixes=TR
+; RUN: opt < %s -passes='bounds-checking<trap;merge=true>'         -S | FileCheck %s --check-prefixes=TR
+; RUN: opt < %s -passes='bounds-checking<rt;merge=true>'           -S | FileCheck %s --check-prefixes=RT
+; RUN: opt < %s -passes='bounds-checking<rt-abort;merge=true>'     -S | FileCheck %s --check-prefixes=RTABORT
+; RUN: opt < %s -passes='bounds-checking<min-rt;merge=true>'       -S | FileCheck %s --check-prefixes=MINRT
+; RUN: opt < %s -passes='bounds-checking<min-rt-abort;merge=true>' -S | FileCheck %s --check-prefixes=MINRTABORT
+;
+; RUN: opt < %s -passes='bounds-checking<merge=false>'              -S | FileCheck %s --check-prefixes=TR-NOMERGE
+; RUN: opt < %s -passes='bounds-checking<trap;merge=false>'         -S | FileCheck %s --check-prefixes=TR-NOMERGE
+; RUN: opt < %s -passes='bounds-checking<rt;merge=false>'           -S | FileCheck %s --check-prefixes=RT-NOMERGE
+; RUN: opt < %s -passes='bounds-checking<rt-abort;merge=false>'     -S | FileCheck %s --check-prefixes=RTABORT-NOMERGE
+; RUN: opt < %s -passes='bounds-checking<min-rt;merge=false>'       -S | FileCheck %s --check-prefixes=MINRT-NOMERGE
+; RUN: opt < %s -passes='bounds-checking<min-rt-abort;merge=false>' -S | FileCheck %s --check-prefixes=MINRTABORT-NOMERGE
 
 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"
 
@@ -88,8 +103,100 @@ define void @f1(i64 %x) nounwind {
 ; MINRTABORT:       [[TRAP]]:
 ; MINRTABORT-NEXT:    call void @__ubsan_handle_local_out_of_bounds_minimal_abort() #[[ATTR1:[0-9]+]]
 ; MINRTABORT-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-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-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]+]]
+; MINRTA...
[truncated]

Copy link

github-actions bot commented Dec 20, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@thurstond thurstond requested a review from vitalybuka December 20, 2024 06:29
@thurstond thurstond merged commit 5bb6503 into llvm:main Dec 20, 2024
6 of 8 checks passed
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 Clang issues not falling into any other category llvm:transforms
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants