Skip to content

Commit 55e87a7

Browse files
authored
[BoundsChecking] Add parameters to pass (#119894)
This check is a part of UBSAN, but does not support verbose output like other UBSAN checks. This is a step to fix that.
1 parent dc936f3 commit 55e87a7

File tree

6 files changed

+170
-3
lines changed

6 files changed

+170
-3
lines changed

clang/lib/CodeGen/BackendUtil.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1029,7 +1029,8 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
10291029
if (LangOpts.Sanitize.has(SanitizerKind::LocalBounds))
10301030
PB.registerScalarOptimizerLateEPCallback(
10311031
[](FunctionPassManager &FPM, OptimizationLevel Level) {
1032-
FPM.addPass(BoundsCheckingPass());
1032+
FPM.addPass(
1033+
BoundsCheckingPass(BoundsCheckingPass::ReportingMode::Trap));
10331034
});
10341035

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

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,25 @@ class Function;
1616

1717
/// A pass to instrument code and perform run-time bounds checking on loads,
1818
/// stores, and other memory intrinsics.
19-
struct BoundsCheckingPass : PassInfoMixin<BoundsCheckingPass> {
19+
class BoundsCheckingPass : public PassInfoMixin<BoundsCheckingPass> {
20+
public:
21+
enum class ReportingMode {
22+
Trap,
23+
MinRuntime,
24+
MinRuntimeAbort,
25+
FullRuntime,
26+
FullRuntimeAbort,
27+
};
28+
29+
private:
30+
ReportingMode Mode = ReportingMode::Trap;
31+
32+
public:
33+
BoundsCheckingPass(ReportingMode Mode) : Mode(Mode) {}
2034
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
2135
static bool isRequired() { return true; }
36+
void printPipeline(raw_ostream &OS,
37+
function_ref<StringRef(StringRef)> MapClassName2PassName);
2238
};
2339

2440
} // end namespace llvm

llvm/lib/Passes/PassBuilder.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1282,6 +1282,33 @@ parseRegAllocFastPassOptions(PassBuilder &PB, StringRef Params) {
12821282
return Opts;
12831283
}
12841284

1285+
Expected<BoundsCheckingPass::ReportingMode>
1286+
parseBoundsCheckingOptions(StringRef Params) {
1287+
BoundsCheckingPass::ReportingMode Mode =
1288+
BoundsCheckingPass::ReportingMode::Trap;
1289+
while (!Params.empty()) {
1290+
StringRef ParamName;
1291+
std::tie(ParamName, Params) = Params.split(';');
1292+
if (ParamName == "trap") {
1293+
Mode = BoundsCheckingPass::ReportingMode::Trap;
1294+
} else if (ParamName == "rt") {
1295+
Mode = BoundsCheckingPass::ReportingMode::FullRuntime;
1296+
} else if (ParamName == "rt-abort") {
1297+
Mode = BoundsCheckingPass::ReportingMode::FullRuntimeAbort;
1298+
} else if (ParamName == "min-rt") {
1299+
Mode = BoundsCheckingPass::ReportingMode::MinRuntime;
1300+
} else if (ParamName == "min-rt-abort") {
1301+
Mode = BoundsCheckingPass::ReportingMode::MinRuntimeAbort;
1302+
} else {
1303+
return make_error<StringError>(
1304+
formatv("invalid BoundsChecking pass parameter '{0}' ", ParamName)
1305+
.str(),
1306+
inconvertibleErrorCode());
1307+
}
1308+
}
1309+
return Mode;
1310+
}
1311+
12851312
} // namespace
12861313

12871314
/// Tests whether a pass name starts with a valid prefix for a default pipeline

llvm/lib/Passes/PassRegistry.def

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,6 @@ FUNCTION_PASS("assume-builder", AssumeBuilderPass())
340340
FUNCTION_PASS("assume-simplify", AssumeSimplifyPass())
341341
FUNCTION_PASS("atomic-expand", AtomicExpandPass(TM))
342342
FUNCTION_PASS("bdce", BDCEPass())
343-
FUNCTION_PASS("bounds-checking", BoundsCheckingPass())
344343
FUNCTION_PASS("break-crit-edges", BreakCriticalEdgesPass())
345344
FUNCTION_PASS("callbr-prepare", CallBrPreparePass())
346345
FUNCTION_PASS("callsite-splitting", CallSiteSplittingPass())
@@ -622,6 +621,12 @@ FUNCTION_PASS_WITH_PARAMS(
622621
return WinEHPreparePass(DemoteCatchSwitchPHIOnly);
623622
},
624623
parseWinEHPrepareOptions, "demote-catchswitch-only")
624+
FUNCTION_PASS_WITH_PARAMS(
625+
"bounds-checking", "BoundsCheckingPass",
626+
[](BoundsCheckingPass::ReportingMode Mode) {
627+
return BoundsCheckingPass(Mode);
628+
},
629+
parseBoundsCheckingOptions, "trap")
625630
#undef FUNCTION_PASS_WITH_PARAMS
626631

627632
#ifndef LOOPNEST_PASS

llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,3 +229,26 @@ PreservedAnalyses BoundsCheckingPass::run(Function &F, FunctionAnalysisManager &
229229

230230
return PreservedAnalyses::none();
231231
}
232+
233+
void BoundsCheckingPass::printPipeline(
234+
raw_ostream &OS, function_ref<StringRef(StringRef)> MapClassName2PassName) {
235+
static_cast<PassInfoMixin<BoundsCheckingPass> *>(this)->printPipeline(
236+
OS, MapClassName2PassName);
237+
switch (Mode) {
238+
case ReportingMode::Trap:
239+
OS << "<trap>";
240+
break;
241+
case ReportingMode::MinRuntime:
242+
OS << "<min-rt>";
243+
break;
244+
case ReportingMode::MinRuntimeAbort:
245+
OS << "<min-rt-abort>";
246+
break;
247+
case ReportingMode::FullRuntime:
248+
OS << "<rt>";
249+
break;
250+
case ReportingMode::FullRuntimeAbort:
251+
OS << "<rt-abort>";
252+
break;
253+
}
254+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
2+
; RUN: opt < %s -passes=bounds-checking -S | FileCheck %s --check-prefixes=TR
3+
; RUN: opt < %s -passes='bounds-checking<trap>' -S | FileCheck %s --check-prefixes=TR
4+
; RUN: opt < %s -passes='bounds-checking<rt>' -S | FileCheck %s --check-prefixes=RT
5+
; RUN: opt < %s -passes='bounds-checking<rt-abort>' -S | FileCheck %s --check-prefixes=RTABORT
6+
; RUN: opt < %s -passes='bounds-checking<min-rt>' -S | FileCheck %s --check-prefixes=MINRT
7+
; RUN: opt < %s -passes='bounds-checking<min-rt-abort>' -S | FileCheck %s --check-prefixes=MINRTABORT
8+
9+
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"
10+
11+
define void @f1(i64 %x) nounwind {
12+
; TR-LABEL: define void @f1(
13+
; TR-SAME: i64 [[X:%.*]]) #[[ATTR0:[0-9]+]] {
14+
; TR-NEXT: [[TMP1:%.*]] = mul i64 16, [[X]]
15+
; TR-NEXT: [[TMP2:%.*]] = alloca i128, i64 [[X]], align 8
16+
; TR-NEXT: [[TMP3:%.*]] = sub i64 [[TMP1]], 0
17+
; TR-NEXT: [[TMP4:%.*]] = icmp ult i64 [[TMP3]], 16
18+
; TR-NEXT: [[TMP5:%.*]] = or i1 false, [[TMP4]]
19+
; TR-NEXT: [[TMP6:%.*]] = or i1 false, [[TMP5]]
20+
; TR-NEXT: br i1 [[TMP6]], label %[[TRAP:.*]], label %[[BB7:.*]]
21+
; TR: [[BB7]]:
22+
; TR-NEXT: [[TMP8:%.*]] = load i128, ptr [[TMP2]], align 4
23+
; TR-NEXT: ret void
24+
; TR: [[TRAP]]:
25+
; TR-NEXT: call void @llvm.trap() #[[ATTR2:[0-9]+]]
26+
; TR-NEXT: unreachable
27+
;
28+
; RT-LABEL: define void @f1(
29+
; RT-SAME: i64 [[X:%.*]]) #[[ATTR0:[0-9]+]] {
30+
; RT-NEXT: [[TMP1:%.*]] = mul i64 16, [[X]]
31+
; RT-NEXT: [[TMP2:%.*]] = alloca i128, i64 [[X]], align 8
32+
; RT-NEXT: [[TMP3:%.*]] = sub i64 [[TMP1]], 0
33+
; RT-NEXT: [[TMP4:%.*]] = icmp ult i64 [[TMP3]], 16
34+
; RT-NEXT: [[TMP5:%.*]] = or i1 false, [[TMP4]]
35+
; RT-NEXT: [[TMP6:%.*]] = or i1 false, [[TMP5]]
36+
; RT-NEXT: br i1 [[TMP6]], label %[[TRAP:.*]], label %[[BB7:.*]]
37+
; RT: [[BB7]]:
38+
; RT-NEXT: [[TMP8:%.*]] = load i128, ptr [[TMP2]], align 4
39+
; RT-NEXT: ret void
40+
; RT: [[TRAP]]:
41+
; RT-NEXT: call void @llvm.trap() #[[ATTR2:[0-9]+]]
42+
; RT-NEXT: unreachable
43+
;
44+
; RTABORT-LABEL: define void @f1(
45+
; RTABORT-SAME: i64 [[X:%.*]]) #[[ATTR0:[0-9]+]] {
46+
; RTABORT-NEXT: [[TMP1:%.*]] = mul i64 16, [[X]]
47+
; RTABORT-NEXT: [[TMP2:%.*]] = alloca i128, i64 [[X]], align 8
48+
; RTABORT-NEXT: [[TMP3:%.*]] = sub i64 [[TMP1]], 0
49+
; RTABORT-NEXT: [[TMP4:%.*]] = icmp ult i64 [[TMP3]], 16
50+
; RTABORT-NEXT: [[TMP5:%.*]] = or i1 false, [[TMP4]]
51+
; RTABORT-NEXT: [[TMP6:%.*]] = or i1 false, [[TMP5]]
52+
; RTABORT-NEXT: br i1 [[TMP6]], label %[[TRAP:.*]], label %[[BB7:.*]]
53+
; RTABORT: [[BB7]]:
54+
; RTABORT-NEXT: [[TMP8:%.*]] = load i128, ptr [[TMP2]], align 4
55+
; RTABORT-NEXT: ret void
56+
; RTABORT: [[TRAP]]:
57+
; RTABORT-NEXT: call void @llvm.trap() #[[ATTR2:[0-9]+]]
58+
; RTABORT-NEXT: unreachable
59+
;
60+
; MINRT-LABEL: define void @f1(
61+
; MINRT-SAME: i64 [[X:%.*]]) #[[ATTR0:[0-9]+]] {
62+
; MINRT-NEXT: [[TMP1:%.*]] = mul i64 16, [[X]]
63+
; MINRT-NEXT: [[TMP2:%.*]] = alloca i128, i64 [[X]], align 8
64+
; MINRT-NEXT: [[TMP3:%.*]] = sub i64 [[TMP1]], 0
65+
; MINRT-NEXT: [[TMP4:%.*]] = icmp ult i64 [[TMP3]], 16
66+
; MINRT-NEXT: [[TMP5:%.*]] = or i1 false, [[TMP4]]
67+
; MINRT-NEXT: [[TMP6:%.*]] = or i1 false, [[TMP5]]
68+
; MINRT-NEXT: br i1 [[TMP6]], label %[[TRAP:.*]], label %[[BB7:.*]]
69+
; MINRT: [[BB7]]:
70+
; MINRT-NEXT: [[TMP8:%.*]] = load i128, ptr [[TMP2]], align 4
71+
; MINRT-NEXT: ret void
72+
; MINRT: [[TRAP]]:
73+
; MINRT-NEXT: call void @llvm.trap() #[[ATTR2:[0-9]+]]
74+
; MINRT-NEXT: unreachable
75+
;
76+
; MINRTABORT-LABEL: define void @f1(
77+
; MINRTABORT-SAME: i64 [[X:%.*]]) #[[ATTR0:[0-9]+]] {
78+
; MINRTABORT-NEXT: [[TMP1:%.*]] = mul i64 16, [[X]]
79+
; MINRTABORT-NEXT: [[TMP2:%.*]] = alloca i128, i64 [[X]], align 8
80+
; MINRTABORT-NEXT: [[TMP3:%.*]] = sub i64 [[TMP1]], 0
81+
; MINRTABORT-NEXT: [[TMP4:%.*]] = icmp ult i64 [[TMP3]], 16
82+
; MINRTABORT-NEXT: [[TMP5:%.*]] = or i1 false, [[TMP4]]
83+
; MINRTABORT-NEXT: [[TMP6:%.*]] = or i1 false, [[TMP5]]
84+
; MINRTABORT-NEXT: br i1 [[TMP6]], label %[[TRAP:.*]], label %[[BB7:.*]]
85+
; MINRTABORT: [[BB7]]:
86+
; MINRTABORT-NEXT: [[TMP8:%.*]] = load i128, ptr [[TMP2]], align 4
87+
; MINRTABORT-NEXT: ret void
88+
; MINRTABORT: [[TRAP]]:
89+
; MINRTABORT-NEXT: call void @llvm.trap() #[[ATTR2:[0-9]+]]
90+
; MINRTABORT-NEXT: unreachable
91+
;
92+
%1 = alloca i128, i64 %x
93+
%3 = load i128, ptr %1, align 4
94+
ret void
95+
}

0 commit comments

Comments
 (0)