Skip to content

Commit ee51ed7

Browse files
committed
Remove -bounds-checking-unique-traps (replace with -fno-sanitize-merge=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.
1 parent cc7d084 commit ee51ed7

File tree

9 files changed

+178
-39
lines changed

9 files changed

+178
-39
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -445,9 +445,10 @@ New Compiler Flags
445445
- The ``-Warray-compare-cxx26`` warning has been added to warn about array comparison
446446
starting from C++26, this warning is enabled as an error by default.
447447

448-
- '-fsanitize-merge' (default) and '-fno-sanitize-merge' have been added for
449-
fine-grained control of which UBSan checks are allowed to be merged by the
450-
backend (for example, -fno-sanitize-merge=bool,enum).
448+
- ``-fsanitize-merge`` (default) and ``-fno-sanitize-merge`` have been added for
449+
fine-grained, unified control of which UBSan checks can potentially be merged
450+
by the compiler (for example,
451+
``-fno-sanitize-merge=bool,enum,array-bounds,local-bounds``).
451452

452453
Deprecated Compiler Flags
453454
-------------------------
@@ -488,8 +489,11 @@ Removed Compiler Flags
488489
derivatives) is now removed, since it's no longer possible to suppress the
489490
diagnostic (see above). Users can expect an `unknown warning` diagnostic if
490491
it's still in use.
491-
- The experimental flag '-ubsan-unique-traps' has been removed. It is
492-
superseded by '-fno-sanitize-merge'.
492+
- The experimental flags '-ubsan-unique-traps' and
493+
'-bounds-checking-unique-traps' have been removed. The combination of the
494+
two flags is equivalent to '-fno-sanitize-merge' with no parameters.
495+
'-bounds-checking-unique-traps' can be selectively controlled via
496+
'-f(no-)sanitize-merge=local-bounds'.
493497

494498
Attribute Changes in Clang
495499
--------------------------

clang/lib/CodeGen/BackendUtil.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1030,6 +1030,8 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
10301030
PB.registerScalarOptimizerLateEPCallback(
10311031
[this](FunctionPassManager &FPM, OptimizationLevel Level) {
10321032
BoundsCheckingPass::ReportingMode Mode;
1033+
bool Merge = CodeGenOpts.SanitizeMergeHandlers.has(SanitizerKind::LocalBounds);
1034+
10331035
if (CodeGenOpts.SanitizeTrap.has(SanitizerKind::LocalBounds)) {
10341036
Mode = BoundsCheckingPass::ReportingMode::Trap;
10351037
} else if (CodeGenOpts.SanitizeMinimalRuntime) {
@@ -1041,7 +1043,8 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
10411043
? BoundsCheckingPass::ReportingMode::FullRuntime
10421044
: BoundsCheckingPass::ReportingMode::FullRuntimeAbort;
10431045
}
1044-
FPM.addPass(BoundsCheckingPass(Mode));
1046+
BoundsCheckingPass::BoundsCheckingOptions Options(Mode, Merge);
1047+
FPM.addPass(BoundsCheckingPass(Options));
10451048
});
10461049

10471050
// Don't add sanitizers if we are here from ThinLTO PostLink. That already

clang/test/CodeGen/bounds-checking.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
// RUN: %clang_cc1 -fsanitize=local-bounds -fsanitize-trap=local-bounds -emit-llvm -triple x86_64-apple-darwin10 %s -o - | FileCheck %s
2-
// RUN: %clang_cc1 -fsanitize=array-bounds -O -emit-llvm -triple x86_64-apple-darwin10 %s -o - | not FileCheck %s
1+
// N.B. The clang driver defaults to -fsanitize-merge but clang_cc1 effectively
2+
// defaults to -fno-sanitize-merge.
33
// RUN: %clang_cc1 -fsanitize=array-bounds -O -fsanitize-trap=array-bounds -emit-llvm -triple x86_64-apple-darwin10 -DNO_DYNAMIC %s -o - | FileCheck %s
4+
// RUN: %clang_cc1 -fsanitize=array-bounds -O -emit-llvm -triple x86_64-apple-darwin10 %s -o - | not FileCheck %s
45
//
5-
// 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
6-
// 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
6+
// RUN: %clang_cc1 -fsanitize=local-bounds -fsanitize-trap=local-bounds -emit-llvm -triple x86_64-apple-darwin10 %s -o - | FileCheck %s
7+
//
8+
// 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
9+
// 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
10+
// 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
711
//
8-
// N.B. The clang driver defaults to -fsanitize-merge but clang_cc1 effectively
9-
// defaults to -fno-sanitize-merge.
1012
// 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
1113
// 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
1214
// 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

llvm/include/llvm/Transforms/Instrumentation/BoundsChecking.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class Function;
1717
/// A pass to instrument code and perform run-time bounds checking on loads,
1818
/// stores, and other memory intrinsics.
1919
class BoundsCheckingPass : public PassInfoMixin<BoundsCheckingPass> {
20+
2021
public:
2122
enum class ReportingMode {
2223
Trap,
@@ -26,15 +27,21 @@ class BoundsCheckingPass : public PassInfoMixin<BoundsCheckingPass> {
2627
FullRuntimeAbort,
2728
};
2829

29-
private:
30-
ReportingMode Mode = ReportingMode::Trap;
30+
struct BoundsCheckingOptions {
31+
BoundsCheckingOptions(ReportingMode Mode, bool Merge);
3132

32-
public:
33-
BoundsCheckingPass(ReportingMode Mode) : Mode(Mode) {}
33+
ReportingMode Mode;
34+
bool Merge;
35+
};
36+
37+
BoundsCheckingPass(BoundsCheckingOptions Options) : Options(Options) {}
3438
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
3539
static bool isRequired() { return true; }
3640
void printPipeline(raw_ostream &OS,
3741
function_ref<StringRef(StringRef)> MapClassName2PassName);
42+
43+
private:
44+
BoundsCheckingOptions Options;
3845
};
3946

4047
} // end namespace llvm

llvm/lib/Passes/PassBuilder.cpp

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1281,31 +1281,42 @@ parseRegAllocFastPassOptions(PassBuilder &PB, StringRef Params) {
12811281
return Opts;
12821282
}
12831283

1284-
Expected<BoundsCheckingPass::ReportingMode>
1284+
Expected<BoundsCheckingPass::BoundsCheckingOptions>
12851285
parseBoundsCheckingOptions(StringRef Params) {
1286-
BoundsCheckingPass::ReportingMode Mode =
1287-
BoundsCheckingPass::ReportingMode::Trap;
1286+
BoundsCheckingPass::BoundsCheckingOptions Options (BoundsCheckingPass::ReportingMode::Trap, true);
12881287
while (!Params.empty()) {
12891288
StringRef ParamName;
12901289
std::tie(ParamName, Params) = Params.split(';');
12911290
if (ParamName == "trap") {
1292-
Mode = BoundsCheckingPass::ReportingMode::Trap;
1291+
Options.Mode = BoundsCheckingPass::ReportingMode::Trap;
12931292
} else if (ParamName == "rt") {
1294-
Mode = BoundsCheckingPass::ReportingMode::FullRuntime;
1293+
Options.Mode = BoundsCheckingPass::ReportingMode::FullRuntime;
12951294
} else if (ParamName == "rt-abort") {
1296-
Mode = BoundsCheckingPass::ReportingMode::FullRuntimeAbort;
1295+
Options.Mode = BoundsCheckingPass::ReportingMode::FullRuntimeAbort;
12971296
} else if (ParamName == "min-rt") {
1298-
Mode = BoundsCheckingPass::ReportingMode::MinRuntime;
1297+
Options.Mode = BoundsCheckingPass::ReportingMode::MinRuntime;
12991298
} else if (ParamName == "min-rt-abort") {
1300-
Mode = BoundsCheckingPass::ReportingMode::MinRuntimeAbort;
1299+
Options.Mode = BoundsCheckingPass::ReportingMode::MinRuntimeAbort;
1300+
} else if (ParamName.consume_front("merge=")) {
1301+
if (ParamName == "true")
1302+
Options.Merge = true;
1303+
else if (ParamName == "false")
1304+
Options.Merge = false;
1305+
else {
1306+
return make_error<StringError>(
1307+
formatv("invalid BoundsChecking pass merge parameter: '{0}' ",
1308+
ParamName)
1309+
.str(),
1310+
inconvertibleErrorCode());
1311+
}
13011312
} else {
13021313
return make_error<StringError>(
13031314
formatv("invalid BoundsChecking pass parameter '{0}' ", ParamName)
13041315
.str(),
13051316
inconvertibleErrorCode());
13061317
}
13071318
}
1308-
return Mode;
1319+
return Options;
13091320
}
13101321

13111322
} // namespace

llvm/lib/Passes/PassRegistry.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -624,8 +624,8 @@ FUNCTION_PASS_WITH_PARAMS(
624624
parseWinEHPrepareOptions, "demote-catchswitch-only")
625625
FUNCTION_PASS_WITH_PARAMS(
626626
"bounds-checking", "BoundsCheckingPass",
627-
[](BoundsCheckingPass::ReportingMode Mode) {
628-
return BoundsCheckingPass(Mode);
627+
[](BoundsCheckingPass::BoundsCheckingOptions Options) {
628+
return BoundsCheckingPass(Options);
629629
},
630630
parseBoundsCheckingOptions, "trap")
631631
#undef FUNCTION_PASS_WITH_PARAMS

llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,15 @@ using namespace llvm;
3737
static cl::opt<bool> SingleTrapBB("bounds-checking-single-trap",
3838
cl::desc("Use one trap block per function"));
3939

40-
static cl::opt<bool> DebugTrapBB("bounds-checking-unique-traps",
41-
cl::desc("Always use one trap per check"));
42-
4340
STATISTIC(ChecksAdded, "Bounds checks added");
4441
STATISTIC(ChecksSkipped, "Bounds checks skipped");
4542
STATISTIC(ChecksUnable, "Bounds checks unable to add");
4643

4744
using BuilderTy = IRBuilder<TargetFolder>;
4845

46+
BoundsCheckingPass::BoundsCheckingOptions::BoundsCheckingOptions(ReportingMode Mode, bool Merge)
47+
: Mode(Mode), Merge(Merge) {}
48+
4949
/// Gets the conditions under which memory accessing instructions will overflow.
5050
///
5151
/// \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,
105105
return Or;
106106
}
107107

108-
static CallInst *InsertTrap(BuilderTy &IRB) {
108+
static CallInst *InsertTrap(BuilderTy &IRB, bool DebugTrapBB) {
109109
if (!DebugTrapBB)
110110
return IRB.CreateIntrinsic(Intrinsic::trap, {}, {});
111111
// FIXME: Ideally we would use the SanitizerHandler::OutOfBounds constant.
@@ -169,9 +169,10 @@ struct ReportingOpts {
169169
bool MayReturn = false;
170170
bool UseTrap = false;
171171
bool MinRuntime = false;
172+
bool MayMerge = true;
172173
StringRef Name;
173174

174-
ReportingOpts(BoundsCheckingPass::ReportingMode Mode) {
175+
ReportingOpts(BoundsCheckingPass::ReportingMode Mode, bool Merge) {
175176
switch (Mode) {
176177
case BoundsCheckingPass::ReportingMode::Trap:
177178
UseTrap = true;
@@ -193,6 +194,8 @@ struct ReportingOpts {
193194
Name = "__ubsan_handle_local_out_of_bounds_abort";
194195
break;
195196
}
197+
198+
MayMerge = Merge;
196199
}
197200
};
198201

@@ -253,13 +256,12 @@ static bool addBoundsChecking(Function &F, TargetLibraryInfo &TLI,
253256
BasicBlock *TrapBB = BasicBlock::Create(Fn->getContext(), "trap", Fn);
254257
IRB.SetInsertPoint(TrapBB);
255258

259+
bool DebugTrapBB = !Opts.MayMerge;
256260
CallInst *TrapCall = Opts.UseTrap
257-
? InsertTrap(IRB)
261+
? InsertTrap(IRB, DebugTrapBB)
258262
: InsertCall(IRB, Opts.MayReturn, Opts.Name);
259-
if (DebugTrapBB) {
260-
// FIXME: Pass option form clang.
263+
if (DebugTrapBB)
261264
TrapCall->addFnAttr(llvm::Attribute::NoMerge);
262-
}
263265

264266
TrapCall->setDoesNotThrow();
265267
TrapCall->setDebugLoc(DebugLoc);
@@ -289,7 +291,7 @@ PreservedAnalyses BoundsCheckingPass::run(Function &F, FunctionAnalysisManager &
289291
auto &TLI = AM.getResult<TargetLibraryAnalysis>(F);
290292
auto &SE = AM.getResult<ScalarEvolutionAnalysis>(F);
291293

292-
if (!addBoundsChecking(F, TLI, SE, ReportingOpts(Mode)))
294+
if (!addBoundsChecking(F, TLI, SE, ReportingOpts(Options.Mode, Options.Merge)))
293295
return PreservedAnalyses::all();
294296

295297
return PreservedAnalyses::none();
@@ -299,7 +301,7 @@ void BoundsCheckingPass::printPipeline(
299301
raw_ostream &OS, function_ref<StringRef(StringRef)> MapClassName2PassName) {
300302
static_cast<PassInfoMixin<BoundsCheckingPass> *>(this)->printPipeline(
301303
OS, MapClassName2PassName);
302-
switch (Mode) {
304+
switch (Options.Mode) {
303305
case ReportingMode::Trap:
304306
OS << "<trap>";
305307
break;

llvm/test/Instrumentation/BoundsChecking/runtimes.ll

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,21 @@
55
; RUN: opt < %s -passes='bounds-checking<rt-abort>' -S | FileCheck %s --check-prefixes=RTABORT
66
; RUN: opt < %s -passes='bounds-checking<min-rt>' -S | FileCheck %s --check-prefixes=MINRT
77
; RUN: opt < %s -passes='bounds-checking<min-rt-abort>' -S | FileCheck %s --check-prefixes=MINRTABORT
8+
;
9+
; merge defaults to true
10+
; RUN: opt < %s -passes='bounds-checking<merge=true>' -S | FileCheck %s --check-prefixes=TR
11+
; RUN: opt < %s -passes='bounds-checking<trap;merge=true>' -S | FileCheck %s --check-prefixes=TR
12+
; RUN: opt < %s -passes='bounds-checking<rt;merge=true>' -S | FileCheck %s --check-prefixes=RT
13+
; RUN: opt < %s -passes='bounds-checking<rt-abort;merge=true>' -S | FileCheck %s --check-prefixes=RTABORT
14+
; RUN: opt < %s -passes='bounds-checking<min-rt;merge=true>' -S | FileCheck %s --check-prefixes=MINRT
15+
; RUN: opt < %s -passes='bounds-checking<min-rt-abort;merge=true>' -S | FileCheck %s --check-prefixes=MINRTABORT
16+
;
17+
; RUN: opt < %s -passes='bounds-checking<merge=false>' -S | FileCheck %s --check-prefixes=TR-NOMERGE
18+
; RUN: opt < %s -passes='bounds-checking<trap;merge=false>' -S | FileCheck %s --check-prefixes=TR-NOMERGE
19+
; RUN: opt < %s -passes='bounds-checking<rt;merge=false>' -S | FileCheck %s --check-prefixes=RT-NOMERGE
20+
; RUN: opt < %s -passes='bounds-checking<rt-abort;merge=false>' -S | FileCheck %s --check-prefixes=RTABORT-NOMERGE
21+
; RUN: opt < %s -passes='bounds-checking<min-rt;merge=false>' -S | FileCheck %s --check-prefixes=MINRT-NOMERGE
22+
; RUN: opt < %s -passes='bounds-checking<min-rt-abort;merge=false>' -S | FileCheck %s --check-prefixes=MINRTABORT-NOMERGE
823

924
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"
1025

@@ -88,8 +103,100 @@ define void @f1(i64 %x) nounwind {
88103
; MINRTABORT: [[TRAP]]:
89104
; MINRTABORT-NEXT: call void @__ubsan_handle_local_out_of_bounds_minimal_abort() #[[ATTR1:[0-9]+]]
90105
; MINRTABORT-NEXT: unreachable
106+
;
107+
; TR-NOMERGE-LABEL: define void @f1(
108+
; TR-NOMERGE-SAME: i64 [[X:%.*]]) #[[ATTR0:[0-9]+]] {
109+
; TR-NOMERGE-NEXT: [[TMP1:%.*]] = mul i64 16, [[X]]
110+
; TR-NOMERGE-NEXT: [[TMP2:%.*]] = alloca i128, i64 [[X]], align 8
111+
; TR-NOMERGE-NEXT: [[TMP3:%.*]] = sub i64 [[TMP1]], 0
112+
; TR-NOMERGE-NEXT: [[TMP4:%.*]] = icmp ult i64 [[TMP3]], 16
113+
; TR-NOMERGE-NEXT: [[TMP5:%.*]] = or i1 false, [[TMP4]]
114+
; TR-NOMERGE-NEXT: [[TMP6:%.*]] = or i1 false, [[TMP5]]
115+
; TR-NOMERGE-NEXT: br i1 [[TMP6]], label %[[TRAP:.*]], label %[[BB7:.*]]
116+
; TR-NOMERGE: [[BB7]]:
117+
; TR-NOMERGE-NEXT: [[TMP8:%.*]] = load i128, ptr [[TMP2]], align 4
118+
; TR-NOMERGE-NEXT: ret void
119+
; TR-NOMERGE: [[TRAP]]:
120+
; TR-NOMERGE-NEXT: call void @llvm.ubsantrap(i8 3) #[[ATTR2:[0-9]+]]
121+
; TR-NOMERGE-NEXT: unreachable
122+
;
123+
; RT-NOMERGE-LABEL: define void @f1(
124+
; RT-NOMERGE-SAME: i64 [[X:%.*]]) #[[ATTR0:[0-9]+]] {
125+
; RT-NOMERGE-NEXT: [[TMP1:%.*]] = mul i64 16, [[X]]
126+
; RT-NOMERGE-NEXT: [[TMP2:%.*]] = alloca i128, i64 [[X]], align 8
127+
; RT-NOMERGE-NEXT: [[TMP3:%.*]] = sub i64 [[TMP1]], 0
128+
; RT-NOMERGE-NEXT: [[TMP4:%.*]] = icmp ult i64 [[TMP3]], 16
129+
; RT-NOMERGE-NEXT: [[TMP5:%.*]] = or i1 false, [[TMP4]]
130+
; RT-NOMERGE-NEXT: [[TMP6:%.*]] = or i1 false, [[TMP5]]
131+
; RT-NOMERGE-NEXT: br i1 [[TMP6]], label %[[TRAP:.*]], label %[[BB7:.*]]
132+
; RT-NOMERGE: [[BB7]]:
133+
; RT-NOMERGE-NEXT: [[TMP8:%.*]] = load i128, ptr [[TMP2]], align 4
134+
; RT-NOMERGE-NEXT: ret void
135+
; RT-NOMERGE: [[TRAP]]:
136+
; RT-NOMERGE-NEXT: call void @__ubsan_handle_local_out_of_bounds() #[[ATTR1:[0-9]+]]
137+
; RT-NOMERGE-NEXT: br label %[[BB7]]
138+
;
139+
; RTABORT-NOMERGE-LABEL: define void @f1(
140+
; RTABORT-NOMERGE-SAME: i64 [[X:%.*]]) #[[ATTR0:[0-9]+]] {
141+
; RTABORT-NOMERGE-NEXT: [[TMP1:%.*]] = mul i64 16, [[X]]
142+
; RTABORT-NOMERGE-NEXT: [[TMP2:%.*]] = alloca i128, i64 [[X]], align 8
143+
; RTABORT-NOMERGE-NEXT: [[TMP3:%.*]] = sub i64 [[TMP1]], 0
144+
; RTABORT-NOMERGE-NEXT: [[TMP4:%.*]] = icmp ult i64 [[TMP3]], 16
145+
; RTABORT-NOMERGE-NEXT: [[TMP5:%.*]] = or i1 false, [[TMP4]]
146+
; RTABORT-NOMERGE-NEXT: [[TMP6:%.*]] = or i1 false, [[TMP5]]
147+
; RTABORT-NOMERGE-NEXT: br i1 [[TMP6]], label %[[TRAP:.*]], label %[[BB7:.*]]
148+
; RTABORT-NOMERGE: [[BB7]]:
149+
; RTABORT-NOMERGE-NEXT: [[TMP8:%.*]] = load i128, ptr [[TMP2]], align 4
150+
; RTABORT-NOMERGE-NEXT: ret void
151+
; RTABORT-NOMERGE: [[TRAP]]:
152+
; RTABORT-NOMERGE-NEXT: call void @__ubsan_handle_local_out_of_bounds_abort() #[[ATTR2:[0-9]+]]
153+
; RTABORT-NOMERGE-NEXT: unreachable
154+
;
155+
; MINRT-NOMERGE-LABEL: define void @f1(
156+
; MINRT-NOMERGE-SAME: i64 [[X:%.*]]) #[[ATTR0:[0-9]+]] {
157+
; MINRT-NOMERGE-NEXT: [[TMP1:%.*]] = mul i64 16, [[X]]
158+
; MINRT-NOMERGE-NEXT: [[TMP2:%.*]] = alloca i128, i64 [[X]], align 8
159+
; MINRT-NOMERGE-NEXT: [[TMP3:%.*]] = sub i64 [[TMP1]], 0
160+
; MINRT-NOMERGE-NEXT: [[TMP4:%.*]] = icmp ult i64 [[TMP3]], 16
161+
; MINRT-NOMERGE-NEXT: [[TMP5:%.*]] = or i1 false, [[TMP4]]
162+
; MINRT-NOMERGE-NEXT: [[TMP6:%.*]] = or i1 false, [[TMP5]]
163+
; MINRT-NOMERGE-NEXT: br i1 [[TMP6]], label %[[TRAP:.*]], label %[[BB7:.*]]
164+
; MINRT-NOMERGE: [[BB7]]:
165+
; MINRT-NOMERGE-NEXT: [[TMP8:%.*]] = load i128, ptr [[TMP2]], align 4
166+
; MINRT-NOMERGE-NEXT: ret void
167+
; MINRT-NOMERGE: [[TRAP]]:
168+
; MINRT-NOMERGE-NEXT: call void @__ubsan_handle_local_out_of_bounds_minimal() #[[ATTR1:[0-9]+]]
169+
; MINRT-NOMERGE-NEXT: br label %[[BB7]]
170+
;
171+
; MINRTABORT-NOMERGE-LABEL: define void @f1(
172+
; MINRTABORT-NOMERGE-SAME: i64 [[X:%.*]]) #[[ATTR0:[0-9]+]] {
173+
; MINRTABORT-NOMERGE-NEXT: [[TMP1:%.*]] = mul i64 16, [[X]]
174+
; MINRTABORT-NOMERGE-NEXT: [[TMP2:%.*]] = alloca i128, i64 [[X]], align 8
175+
; MINRTABORT-NOMERGE-NEXT: [[TMP3:%.*]] = sub i64 [[TMP1]], 0
176+
; MINRTABORT-NOMERGE-NEXT: [[TMP4:%.*]] = icmp ult i64 [[TMP3]], 16
177+
; MINRTABORT-NOMERGE-NEXT: [[TMP5:%.*]] = or i1 false, [[TMP4]]
178+
; MINRTABORT-NOMERGE-NEXT: [[TMP6:%.*]] = or i1 false, [[TMP5]]
179+
; MINRTABORT-NOMERGE-NEXT: br i1 [[TMP6]], label %[[TRAP:.*]], label %[[BB7:.*]]
180+
; MINRTABORT-NOMERGE: [[BB7]]:
181+
; MINRTABORT-NOMERGE-NEXT: [[TMP8:%.*]] = load i128, ptr [[TMP2]], align 4
182+
; MINRTABORT-NOMERGE-NEXT: ret void
183+
; MINRTABORT-NOMERGE: [[TRAP]]:
184+
; MINRTABORT-NOMERGE-NEXT: call void @__ubsan_handle_local_out_of_bounds_minimal_abort() #[[ATTR2:[0-9]+]]
185+
; MINRTABORT-NOMERGE-NEXT: unreachable
91186
;
92187
%1 = alloca i128, i64 %x
93188
%3 = load i128, ptr %1, align 4
94189
ret void
95190
}
191+
192+
; TR: attributes #[[ATTR2]] = { noreturn nounwind }
193+
; RT: attributes #[[ATTR0]] = { nounwind }
194+
; RTABORT: attributes #[[ATTR1]] = { noreturn nounwind }
195+
; MINRT: attributes #[[ATTR0]] = { nounwind }
196+
; MINRTABORT: attributes #[[ATTR1]] = { noreturn nounwind }
197+
198+
; TR-NOMERGE: attributes #[[ATTR2]] = { nomerge noreturn nounwind }
199+
; RT-NOMERGE: attributes #[[ATTR1]] = { nomerge nounwind }
200+
; RTABORT-NOMERGE: attributes #[[ATTR2]] = { nomerge noreturn nounwind }
201+
; MINRT-NOMERGE: attributes #[[ATTR1]] = { nomerge nounwind }
202+
; MINRTABORT-NOMERGE: attributes #[[ATTR2]] = { nomerge noreturn nounwind }

llvm/test/Instrumentation/BoundsChecking/ubsan-unique-traps.ll

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2-
; RUN: opt < %s -passes=bounds-checking -bounds-checking-unique-traps -S | FileCheck %s
2+
; RUN: opt < %s -passes='bounds-checking<merge=false>' -S | FileCheck %s
3+
; RUN: opt < %s -passes='bounds-checking<merge=true>' -S | not FileCheck %s
4+
; RUN: opt < %s -passes=bounds-checking -S | not FileCheck %s
5+
36
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"
47

58
declare noalias ptr @malloc(i64) nounwind allocsize(0)

0 commit comments

Comments
 (0)