Skip to content

Commit 695c74e

Browse files
committed
[LLVM][rtsan] Add NonBlocking Attribute and RealtimeSanitizer pass
1 parent 3f6eb13 commit 695c74e

File tree

15 files changed

+174
-2
lines changed

15 files changed

+174
-2
lines changed

llvm/CODE_OWNERS.TXT

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,3 +263,7 @@ D: C-SKY backend (lib/Target/CSKY/*)
263263
N: Ilia Diachkov
264264
265265
D: SPIR-V backend (lib/Target/SPIRV/*)
266+
267+
N: Christopher Apple, David Trevelyan
268+
269+
D: RealtimeSanitizer (LLVM part)

llvm/include/llvm/Bitcode/LLVMBitCodes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -758,6 +758,7 @@ enum AttributeKindCodes {
758758
ATTR_KIND_SANITIZE_NUMERICAL_STABILITY = 93,
759759
ATTR_KIND_INITIALIZES = 94,
760760
ATTR_KIND_HYBRID_PATCHABLE = 95,
761+
ATTR_KIND_NONBLOCKING = 96,
761762
};
762763

763764
enum ComdatSelectionKindCodes {

llvm/include/llvm/IR/Attributes.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,9 @@ def ReadNone : EnumAttr<"readnone", [ParamAttr]>;
239239
/// Function only reads from memory.
240240
def ReadOnly : EnumAttr<"readonly", [ParamAttr]>;
241241

242+
/// Function is marked to be non-blocking
243+
def NonBlocking : EnumAttr<"nonblocking", [FnAttr]>;
244+
242245
/// Return value is always equal to this argument.
243246
def Returned : EnumAttr<"returned", [ParamAttr]>;
244247

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//===--------- Definition of the RealtimeSanitizer class ---------*- C++
2+
//-*-===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
//
11+
//===----------------------------------------------------------------------===//
12+
#ifndef LLVM_TRANSFORMS_INSTRUMENTATION_REALTIMESANITIZER_H
13+
#define LLVM_TRANSFORMS_INSTRUMENTATION_REALTIMESANITIZER_H
14+
15+
#include "llvm/IR/PassManager.h"
16+
#include "llvm/Transforms/Instrumentation/RealtimeSanitizerOptions.h"
17+
18+
namespace llvm {
19+
20+
struct RealtimeSanitizerOptions {};
21+
22+
class RealtimeSanitizerPass : public PassInfoMixin<RealtimeSanitizerPass> {
23+
public:
24+
RealtimeSanitizerPass(const RealtimeSanitizerOptions &Options);
25+
PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM);
26+
27+
static bool isRequired() { return true; }
28+
29+
private:
30+
RealtimeSanitizerOptions Options{};
31+
};
32+
33+
} // namespace llvm
34+
35+
#endif // LLVM_TRANSFORMS_INSTRUMENTATION_REALTIMESANITIZER_H
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//===--------- Definition of the RealtimeSanitizer options -------*- C++
2+
//-*-===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
// This file defines data types used to set Realtime Sanitizer options.
10+
//===----------------------------------------------------------------------===//
11+
12+
#ifndef LLVM_TRANSFORMS_INSTRUMENTATION_REALTIMESANITIZEROPTIONS_H
13+
#define LLVM_TRANSFORMS_INSTRUMENTATION_REALTIMESANITIZEROPTIONS_H
14+
15+
namespace llvm {} // namespace llvm
16+
17+
#endif

llvm/lib/Bitcode/Reader/BitcodeReader.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2109,6 +2109,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
21092109
return Attribute::ReadOnly;
21102110
case bitc::ATTR_KIND_RETURNED:
21112111
return Attribute::Returned;
2112+
case bitc::ATTR_KIND_NONBLOCKING:
2113+
return Attribute::NonBlocking;
21122114
case bitc::ATTR_KIND_RETURNS_TWICE:
21132115
return Attribute::ReturnsTwice;
21142116
case bitc::ATTR_KIND_S_EXT:

llvm/lib/Bitcode/Writer/BitcodeWriter.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
805805
return bitc::ATTR_KIND_OPTIMIZE_FOR_SIZE;
806806
case Attribute::OptimizeNone:
807807
return bitc::ATTR_KIND_OPTIMIZE_NONE;
808+
case Attribute::NonBlocking:
809+
return bitc::ATTR_KIND_NONBLOCKING;
808810
case Attribute::ReadNone:
809811
return bitc::ATTR_KIND_READ_NONE;
810812
case Attribute::ReadOnly:

llvm/lib/Passes/PassBuilder.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@
198198
#include "llvm/Transforms/Instrumentation/PGOForceFunctionAttrs.h"
199199
#include "llvm/Transforms/Instrumentation/PGOInstrumentation.h"
200200
#include "llvm/Transforms/Instrumentation/PoisonChecking.h"
201+
#include "llvm/Transforms/Instrumentation/RealtimeSanitizer.h"
201202
#include "llvm/Transforms/Instrumentation/SanitizerBinaryMetadata.h"
202203
#include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
203204
#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
@@ -1207,6 +1208,11 @@ parseRegAllocFastPassOptions(PassBuilder &PB, StringRef Params) {
12071208
return Opts;
12081209
}
12091210

1211+
Expected<RealtimeSanitizerOptions> parseRtSanPassOptions(StringRef Params) {
1212+
RealtimeSanitizerOptions Result;
1213+
return Result;
1214+
}
1215+
12101216
} // namespace
12111217

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

llvm/lib/Passes/PassRegistry.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,10 @@ FUNCTION_PASS_WITH_PARAMS(
590590
return WinEHPreparePass(DemoteCatchSwitchPHIOnly);
591591
},
592592
parseWinEHPrepareOptions, "demote-catchswitch-only")
593+
FUNCTION_PASS_WITH_PARAMS(
594+
"rtsan", "RealtimeSanitizerPass",
595+
[](RealtimeSanitizerOptions Opts) { return RealtimeSanitizerPass(Opts); },
596+
parseRtSanPassOptions, "")
593597
#undef FUNCTION_PASS_WITH_PARAMS
594598

595599
#ifndef LOOPNEST_PASS

llvm/lib/Transforms/Instrumentation/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ add_llvm_component_library(LLVMInstrumentation
2525
ValueProfileCollector.cpp
2626
ThreadSanitizer.cpp
2727
HWAddressSanitizer.cpp
28+
RealtimeSanitizer.cpp
2829

2930
ADDITIONAL_HEADER_DIRS
3031
${LLVM_MAIN_INCLUDE_DIR}/llvm/Transforms
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#include "llvm/IR/Analysis.h"
2+
#include "llvm/IR/IRBuilder.h"
3+
#include "llvm/IR/Module.h"
4+
5+
#include "llvm/Transforms/Instrumentation/RealtimeSanitizer.h"
6+
7+
using namespace llvm;
8+
9+
namespace {
10+
11+
void insertCallBeforeInstruction(Function &Fn, Instruction &Instruction,
12+
const char *FunctionName) {
13+
LLVMContext &Context = Fn.getContext();
14+
FunctionType *FuncType = FunctionType::get(Type::getVoidTy(Context), false);
15+
FunctionCallee Func =
16+
Fn.getParent()->getOrInsertFunction(FunctionName, FuncType);
17+
IRBuilder<> Builder{&Instruction};
18+
Builder.CreateCall(Func, {});
19+
}
20+
21+
void insertCallAtFunctionEntryPoint(Function &Fn, const char *InsertFnName) {
22+
23+
insertCallBeforeInstruction(Fn, Fn.front().front(), InsertFnName);
24+
}
25+
26+
void insertCallAtAllFunctionExitPoints(Function &Fn, const char *InsertFnName) {
27+
for (auto &BB : Fn) {
28+
for (auto &I : BB) {
29+
if (auto *RI = dyn_cast<ReturnInst>(&I)) {
30+
insertCallBeforeInstruction(Fn, I, InsertFnName);
31+
}
32+
}
33+
}
34+
}
35+
} // namespace
36+
37+
RealtimeSanitizerPass::RealtimeSanitizerPass(
38+
const RealtimeSanitizerOptions &Options)
39+
: Options{Options} {}
40+
41+
PreservedAnalyses RealtimeSanitizerPass::run(Function &F,
42+
AnalysisManager<Function> &AM) {
43+
if (F.hasFnAttribute(Attribute::NonBlocking)) {
44+
insertCallAtFunctionEntryPoint(F, "__rtsan_realtime_enter");
45+
insertCallAtAllFunctionExitPoints(F, "__rtsan_realtime_exit");
46+
return PreservedAnalyses::none();
47+
}
48+
49+
return PreservedAnalyses::all();
50+
}

llvm/lib/Transforms/Utils/CodeExtractor.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -946,6 +946,7 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs,
946946
case Attribute::NoUnwind:
947947
case Attribute::NoSanitizeBounds:
948948
case Attribute::NoSanitizeCoverage:
949+
case Attribute::NonBlocking:
949950
case Attribute::NullPointerIsValid:
950951
case Attribute::OptimizeForDebugging:
951952
case Attribute::OptForFuzzing:

llvm/test/Bitcode/attributes.ll

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,12 @@ define void @f86() nosanitize_bounds
505505
ret void;
506506
}
507507

508+
; CHECK: define void @f92() #53
509+
define void @f92() nonblocking
510+
{
511+
ret void;
512+
}
513+
508514
; CHECK: define void @f87() [[FNRETTHUNKEXTERN:#[0-9]+]]
509515
define void @f87() fn_ret_thunk_extern { ret void }
510516

@@ -599,6 +605,7 @@ define void @initializes(ptr initializes((-4, 0), (4, 8)) %a) {
599605
; CHECK: attributes #50 = { disable_sanitizer_instrumentation }
600606
; CHECK: attributes #51 = { uwtable(sync) }
601607
; CHECK: attributes #52 = { nosanitize_bounds }
608+
; CHECK: attributes #53 = { nonblocking }
602609
; CHECK: attributes [[FNRETTHUNKEXTERN]] = { fn_ret_thunk_extern }
603610
; CHECK: attributes [[SKIPPROFILE]] = { skipprofile }
604611
; CHECK: attributes [[OPTDEBUG]] = { optdebug }

llvm/test/Bitcode/compatibility.ll

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1564,7 +1564,7 @@ exit:
15641564
; CHECK: select <2 x i1> <i1 true, i1 false>, <2 x i8> <i8 2, i8 3>, <2 x i8> <i8 3, i8 2>
15651565

15661566
call void @f.nobuiltin() builtin
1567-
; CHECK: call void @f.nobuiltin() #52
1567+
; CHECK: call void @f.nobuiltin() #53
15681568

15691569
call fastcc noalias ptr @f.noalias() noinline
15701570
; CHECK: call fastcc noalias ptr @f.noalias() #12
@@ -1991,6 +1991,9 @@ declare void @f.allockind() allockind("alloc,uninitialized")
19911991
declare void @f.sanitize_numerical_stability() sanitize_numerical_stability
19921992
; CHECK: declare void @f.sanitize_numerical_stability() #51
19931993

1994+
declare void @f.nonblocking() nonblocking
1995+
; CHECK: declare void @f.nonblocking() #52
1996+
19941997
; CHECK: declare nofpclass(snan) float @nofpclass_snan(float nofpclass(snan))
19951998
declare nofpclass(snan) float @nofpclass_snan(float nofpclass(snan))
19961999

@@ -2113,7 +2116,8 @@ define float @nofpclass_callsites(float %arg) {
21132116
; CHECK: attributes #49 = { nosanitize_bounds }
21142117
; CHECK: attributes #50 = { allockind("alloc,uninitialized") }
21152118
; CHECK: attributes #51 = { sanitize_numerical_stability }
2116-
; CHECK: attributes #52 = { builtin }
2119+
; CHECK: attributes #52 = { nonblocking }
2120+
; CHECK: attributes #53 = { builtin }
21172121

21182122
;; Metadata
21192123

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
; RUN: opt < %s -passes=rtsan -S | FileCheck %s
2+
3+
; Function Attrs: mustprogress noinline nonblocking optnone ssp uwtable(sync)
4+
define void @violation() #0 {
5+
%1 = alloca ptr, align 8
6+
%2 = call ptr @malloc(i64 noundef 2) #3
7+
store ptr %2, ptr %1, align 8
8+
ret void
9+
}
10+
11+
; Function Attrs: allocsize(0)
12+
declare ptr @malloc(i64 noundef) #1
13+
14+
; Function Attrs: mustprogress noinline norecurse optnone ssp uwtable(sync)
15+
define noundef i32 @main() #2 {
16+
%1 = alloca i32, align 4
17+
store i32 0, ptr %1, align 4
18+
call void @violation() #4
19+
ret i32 0
20+
}
21+
22+
attributes #0 = { mustprogress noinline nonblocking optnone ssp uwtable(sync) }
23+
attributes #1 = { allocsize(0) }
24+
attributes #2 = { mustprogress noinline norecurse optnone ssp uwtable(sync) }
25+
attributes #3 = { allocsize(0) }
26+
attributes #4 = { nonblocking }
27+
28+
; RealtimeSanitizer pass should insert __rtsan_realtime_enter right after function definition
29+
; CHECK: define{{.*}}violation
30+
; CHECK-NEXT: call{{.*}}__rtsan_realtime_enter
31+
32+
; RealtimeSanitizer pass should insert __rtsan_realtime_exit right before function return
33+
; CHECK: call{{.*}}@__rtsan_realtime_exit
34+
; CHECK-NEXT: ret{{.*}}void
35+

0 commit comments

Comments
 (0)