https://github.com/thurstond created https://github.com/llvm/llvm-project/pull/120682
-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. >From ee51ed7bd68df7b2dae3f1426471b34d0388a42f Mon Sep 17 00:00:00 2001 From: Thurston Dang <thurs...@google.com> Date: Fri, 20 Dec 2024 04:11:36 +0000 Subject: [PATCH] Remove -bounds-checking-unique-traps (replace with -fno-sanitize-merge=local-bounds) -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. 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. --- clang/docs/ReleaseNotes.rst | 14 ++- clang/lib/CodeGen/BackendUtil.cpp | 5 +- clang/test/CodeGen/bounds-checking.c | 14 ++- .../Instrumentation/BoundsChecking.h | 15 ++- llvm/lib/Passes/PassBuilder.cpp | 29 +++-- llvm/lib/Passes/PassRegistry.def | 4 +- .../Instrumentation/BoundsChecking.cpp | 24 ++-- .../BoundsChecking/runtimes.ll | 107 ++++++++++++++++++ .../BoundsChecking/ubsan-unique-traps.ll | 5 +- 9 files changed, 178 insertions(+), 39 deletions(-) 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]+]] +; MINRTABORT-NOMERGE-NEXT: unreachable ; %1 = alloca i128, i64 %x %3 = load i128, ptr %1, align 4 ret void } + +; TR: attributes #[[ATTR2]] = { noreturn nounwind } +; RT: attributes #[[ATTR0]] = { nounwind } +; RTABORT: attributes #[[ATTR1]] = { noreturn nounwind } +; MINRT: attributes #[[ATTR0]] = { nounwind } +; MINRTABORT: attributes #[[ATTR1]] = { noreturn nounwind } + +; 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 } diff --git a/llvm/test/Instrumentation/BoundsChecking/ubsan-unique-traps.ll b/llvm/test/Instrumentation/BoundsChecking/ubsan-unique-traps.ll index a3f34007e9b09f..a79db52905e824 100644 --- a/llvm/test/Instrumentation/BoundsChecking/ubsan-unique-traps.ll +++ b/llvm/test/Instrumentation/BoundsChecking/ubsan-unique-traps.ll @@ -1,5 +1,8 @@ ; 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<merge=false>' -S | FileCheck %s +; RUN: opt < %s -passes='bounds-checking<merge=true>' -S | not FileCheck %s +; RUN: opt < %s -passes=bounds-checking -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) _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits