Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
-------------------------
Expand Down Expand Up @@ -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
--------------------------
Expand Down
6 changes: 5 additions & 1 deletion clang/lib/CodeGen/BackendUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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
Expand Down
14 changes: 8 additions & 6 deletions clang/test/CodeGen/bounds-checking.c
Original file line number Diff line number Diff line change
@@ -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
Expand Down
15 changes: 11 additions & 4 deletions llvm/include/llvm/Transforms/Instrumentation/BoundsChecking.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
Expand Down
30 changes: 21 additions & 9 deletions llvm/lib/Passes/PassBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1281,31 +1281,43 @@ 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)
.str(),
inconvertibleErrorCode());
}
}
return Mode;
return Options;
}

} // namespace
Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/Passes/PassRegistry.def
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
26 changes: 15 additions & 11 deletions llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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;
Expand All @@ -193,6 +195,8 @@ struct ReportingOpts {
Name = "__ubsan_handle_local_out_of_bounds_abort";
break;
}

MayMerge = Merge;
}
};

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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();
Expand All @@ -299,7 +303,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;
Expand Down
107 changes: 107 additions & 0 deletions llvm/test/Instrumentation/BoundsChecking/runtimes.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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 }
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
Loading