-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[LLVM][rtsan] Add sanitize_realtime attribute for the realtime sanitizer #100596
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-llvm-transforms @llvm/pr-subscribers-compiler-rt-sanitizer Author: Chris Apple (cjappl) ChangesAdd the RealtimeSanitizer pass to llvm. This also required adding a new "nonblocking" attribute, which will correspond to the nonblocking function effect in clang. Please see the reviewer support document for what our next steps are. The original discourse thread can be found here Full diff: https://github.com/llvm/llvm-project/pull/100596.diff 15 Files Affected:
diff --git a/llvm/CODE_OWNERS.TXT b/llvm/CODE_OWNERS.TXT
index d1620d1cbf870..c996cae8f97c5 100644
--- a/llvm/CODE_OWNERS.TXT
+++ b/llvm/CODE_OWNERS.TXT
@@ -263,3 +263,7 @@ D: C-SKY backend (lib/Target/CSKY/*)
N: Ilia Diachkov
E: [email protected]
D: SPIR-V backend (lib/Target/SPIRV/*)
+
+N: Christopher Apple, David Trevelyan
+E: [email protected], [email protected]
+D: RealtimeSanitizer (LLVM part)
diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
index fb88f2fe75adb..61b046c26a97f 100644
--- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h
+++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
@@ -758,6 +758,7 @@ enum AttributeKindCodes {
ATTR_KIND_SANITIZE_NUMERICAL_STABILITY = 93,
ATTR_KIND_INITIALIZES = 94,
ATTR_KIND_HYBRID_PATCHABLE = 95,
+ ATTR_KIND_NONBLOCKING = 96,
};
enum ComdatSelectionKindCodes {
diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td
index e1bd193891c1e..8d90e912f279c 100644
--- a/llvm/include/llvm/IR/Attributes.td
+++ b/llvm/include/llvm/IR/Attributes.td
@@ -239,6 +239,9 @@ def ReadNone : EnumAttr<"readnone", [ParamAttr]>;
/// Function only reads from memory.
def ReadOnly : EnumAttr<"readonly", [ParamAttr]>;
+/// Function is marked to be non-blocking
+def NonBlocking : EnumAttr<"nonblocking", [FnAttr]>;
+
/// Return value is always equal to this argument.
def Returned : EnumAttr<"returned", [ParamAttr]>;
diff --git a/llvm/include/llvm/Transforms/Instrumentation/RealtimeSanitizer.h b/llvm/include/llvm/Transforms/Instrumentation/RealtimeSanitizer.h
new file mode 100644
index 0000000000000..9cf2448361608
--- /dev/null
+++ b/llvm/include/llvm/Transforms/Instrumentation/RealtimeSanitizer.h
@@ -0,0 +1,35 @@
+//===--------- Definition of the RealtimeSanitizer class ---------*- C++
+//-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_TRANSFORMS_INSTRUMENTATION_REALTIMESANITIZER_H
+#define LLVM_TRANSFORMS_INSTRUMENTATION_REALTIMESANITIZER_H
+
+#include "llvm/IR/PassManager.h"
+#include "llvm/Transforms/Instrumentation/RealtimeSanitizerOptions.h"
+
+namespace llvm {
+
+struct RealtimeSanitizerOptions {};
+
+class RealtimeSanitizerPass : public PassInfoMixin<RealtimeSanitizerPass> {
+public:
+ RealtimeSanitizerPass(const RealtimeSanitizerOptions &Options);
+ PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM);
+
+ static bool isRequired() { return true; }
+
+private:
+ RealtimeSanitizerOptions Options{};
+};
+
+} // namespace llvm
+
+#endif // LLVM_TRANSFORMS_INSTRUMENTATION_REALTIMESANITIZER_H
diff --git a/llvm/include/llvm/Transforms/Instrumentation/RealtimeSanitizerOptions.h b/llvm/include/llvm/Transforms/Instrumentation/RealtimeSanitizerOptions.h
new file mode 100644
index 0000000000000..35376a5647c60
--- /dev/null
+++ b/llvm/include/llvm/Transforms/Instrumentation/RealtimeSanitizerOptions.h
@@ -0,0 +1,17 @@
+//===--------- Definition of the RealtimeSanitizer options -------*- C++
+//-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// This file defines data types used to set Realtime Sanitizer options.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TRANSFORMS_INSTRUMENTATION_REALTIMESANITIZEROPTIONS_H
+#define LLVM_TRANSFORMS_INSTRUMENTATION_REALTIMESANITIZEROPTIONS_H
+
+namespace llvm {} // namespace llvm
+
+#endif
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index 84d624f6cf8fa..a519748bc1c83 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -2109,6 +2109,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
return Attribute::ReadOnly;
case bitc::ATTR_KIND_RETURNED:
return Attribute::Returned;
+ case bitc::ATTR_KIND_NONBLOCKING:
+ return Attribute::NonBlocking;
case bitc::ATTR_KIND_RETURNS_TWICE:
return Attribute::ReturnsTwice;
case bitc::ATTR_KIND_S_EXT:
diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index 324dcbca8137e..d54aeae74a59f 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -805,6 +805,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
return bitc::ATTR_KIND_OPTIMIZE_FOR_SIZE;
case Attribute::OptimizeNone:
return bitc::ATTR_KIND_OPTIMIZE_NONE;
+ case Attribute::NonBlocking:
+ return bitc::ATTR_KIND_NONBLOCKING;
case Attribute::ReadNone:
return bitc::ATTR_KIND_READ_NONE;
case Attribute::ReadOnly:
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index 5dbb1e2f49871..faf3e25cb31d9 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -198,6 +198,7 @@
#include "llvm/Transforms/Instrumentation/PGOForceFunctionAttrs.h"
#include "llvm/Transforms/Instrumentation/PGOInstrumentation.h"
#include "llvm/Transforms/Instrumentation/PoisonChecking.h"
+#include "llvm/Transforms/Instrumentation/RealtimeSanitizer.h"
#include "llvm/Transforms/Instrumentation/SanitizerBinaryMetadata.h"
#include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
@@ -1207,6 +1208,11 @@ parseRegAllocFastPassOptions(PassBuilder &PB, StringRef Params) {
return Opts;
}
+Expected<RealtimeSanitizerOptions> parseRtSanPassOptions(StringRef Params) {
+ RealtimeSanitizerOptions Result;
+ return Result;
+}
+
} // namespace
/// Tests whether a pass name starts with a valid prefix for a default pipeline
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index 3b92823cd283b..f795c7242f958 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -590,6 +590,10 @@ FUNCTION_PASS_WITH_PARAMS(
return WinEHPreparePass(DemoteCatchSwitchPHIOnly);
},
parseWinEHPrepareOptions, "demote-catchswitch-only")
+FUNCTION_PASS_WITH_PARAMS(
+ "rtsan", "RealtimeSanitizerPass",
+ [](RealtimeSanitizerOptions Opts) { return RealtimeSanitizerPass(Opts); },
+ parseRtSanPassOptions, "")
#undef FUNCTION_PASS_WITH_PARAMS
#ifndef LOOPNEST_PASS
diff --git a/llvm/lib/Transforms/Instrumentation/CMakeLists.txt b/llvm/lib/Transforms/Instrumentation/CMakeLists.txt
index 4e3f9e27e0c34..deab37801ff1d 100644
--- a/llvm/lib/Transforms/Instrumentation/CMakeLists.txt
+++ b/llvm/lib/Transforms/Instrumentation/CMakeLists.txt
@@ -25,6 +25,7 @@ add_llvm_component_library(LLVMInstrumentation
ValueProfileCollector.cpp
ThreadSanitizer.cpp
HWAddressSanitizer.cpp
+ RealtimeSanitizer.cpp
ADDITIONAL_HEADER_DIRS
${LLVM_MAIN_INCLUDE_DIR}/llvm/Transforms
diff --git a/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
new file mode 100644
index 0000000000000..2fa2389c4984f
--- /dev/null
+++ b/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
@@ -0,0 +1,50 @@
+#include "llvm/IR/Analysis.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/Module.h"
+
+#include "llvm/Transforms/Instrumentation/RealtimeSanitizer.h"
+
+using namespace llvm;
+
+namespace {
+
+void insertCallBeforeInstruction(Function &Fn, Instruction &Instruction,
+ const char *FunctionName) {
+ LLVMContext &Context = Fn.getContext();
+ FunctionType *FuncType = FunctionType::get(Type::getVoidTy(Context), false);
+ FunctionCallee Func =
+ Fn.getParent()->getOrInsertFunction(FunctionName, FuncType);
+ IRBuilder<> Builder{&Instruction};
+ Builder.CreateCall(Func, {});
+}
+
+void insertCallAtFunctionEntryPoint(Function &Fn, const char *InsertFnName) {
+
+ insertCallBeforeInstruction(Fn, Fn.front().front(), InsertFnName);
+}
+
+void insertCallAtAllFunctionExitPoints(Function &Fn, const char *InsertFnName) {
+ for (auto &BB : Fn) {
+ for (auto &I : BB) {
+ if (auto *RI = dyn_cast<ReturnInst>(&I)) {
+ insertCallBeforeInstruction(Fn, I, InsertFnName);
+ }
+ }
+ }
+}
+} // namespace
+
+RealtimeSanitizerPass::RealtimeSanitizerPass(
+ const RealtimeSanitizerOptions &Options)
+ : Options{Options} {}
+
+PreservedAnalyses RealtimeSanitizerPass::run(Function &F,
+ AnalysisManager<Function> &AM) {
+ if (F.hasFnAttribute(Attribute::NonBlocking)) {
+ insertCallAtFunctionEntryPoint(F, "__rtsan_realtime_enter");
+ insertCallAtAllFunctionExitPoints(F, "__rtsan_realtime_exit");
+ return PreservedAnalyses::none();
+ }
+
+ return PreservedAnalyses::all();
+}
diff --git a/llvm/lib/Transforms/Utils/CodeExtractor.cpp b/llvm/lib/Transforms/Utils/CodeExtractor.cpp
index 5bca5cf8ff91f..1339bbb3842d4 100644
--- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp
+++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp
@@ -946,6 +946,7 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs,
case Attribute::NoUnwind:
case Attribute::NoSanitizeBounds:
case Attribute::NoSanitizeCoverage:
+ case Attribute::NonBlocking:
case Attribute::NullPointerIsValid:
case Attribute::OptimizeForDebugging:
case Attribute::OptForFuzzing:
diff --git a/llvm/test/Bitcode/attributes.ll b/llvm/test/Bitcode/attributes.ll
index f4dc9b9849827..5f8617dad8dfd 100644
--- a/llvm/test/Bitcode/attributes.ll
+++ b/llvm/test/Bitcode/attributes.ll
@@ -505,6 +505,12 @@ define void @f86() nosanitize_bounds
ret void;
}
+; CHECK: define void @f92() #53
+define void @f92() nonblocking
+{
+ ret void;
+}
+
; CHECK: define void @f87() [[FNRETTHUNKEXTERN:#[0-9]+]]
define void @f87() fn_ret_thunk_extern { ret void }
@@ -599,6 +605,7 @@ define void @initializes(ptr initializes((-4, 0), (4, 8)) %a) {
; CHECK: attributes #50 = { disable_sanitizer_instrumentation }
; CHECK: attributes #51 = { uwtable(sync) }
; CHECK: attributes #52 = { nosanitize_bounds }
+; CHECK: attributes #53 = { nonblocking }
; CHECK: attributes [[FNRETTHUNKEXTERN]] = { fn_ret_thunk_extern }
; CHECK: attributes [[SKIPPROFILE]] = { skipprofile }
; CHECK: attributes [[OPTDEBUG]] = { optdebug }
diff --git a/llvm/test/Bitcode/compatibility.ll b/llvm/test/Bitcode/compatibility.ll
index e437c37d8d1c8..1471138b91a9f 100644
--- a/llvm/test/Bitcode/compatibility.ll
+++ b/llvm/test/Bitcode/compatibility.ll
@@ -1564,7 +1564,7 @@ exit:
; CHECK: select <2 x i1> <i1 true, i1 false>, <2 x i8> <i8 2, i8 3>, <2 x i8> <i8 3, i8 2>
call void @f.nobuiltin() builtin
- ; CHECK: call void @f.nobuiltin() #52
+ ; CHECK: call void @f.nobuiltin() #53
call fastcc noalias ptr @f.noalias() noinline
; CHECK: call fastcc noalias ptr @f.noalias() #12
@@ -1991,6 +1991,9 @@ declare void @f.allockind() allockind("alloc,uninitialized")
declare void @f.sanitize_numerical_stability() sanitize_numerical_stability
; CHECK: declare void @f.sanitize_numerical_stability() #51
+declare void @f.nonblocking() nonblocking
+; CHECK: declare void @f.nonblocking() #52
+
; CHECK: declare nofpclass(snan) float @nofpclass_snan(float nofpclass(snan))
declare nofpclass(snan) float @nofpclass_snan(float nofpclass(snan))
@@ -2113,7 +2116,8 @@ define float @nofpclass_callsites(float %arg) {
; CHECK: attributes #49 = { nosanitize_bounds }
; CHECK: attributes #50 = { allockind("alloc,uninitialized") }
; CHECK: attributes #51 = { sanitize_numerical_stability }
-; CHECK: attributes #52 = { builtin }
+; CHECK: attributes #52 = { nonblocking }
+; CHECK: attributes #53 = { builtin }
;; Metadata
diff --git a/llvm/test/Instrumentation/RealtimeSanitizer/rtsan.ll b/llvm/test/Instrumentation/RealtimeSanitizer/rtsan.ll
new file mode 100644
index 0000000000000..222df484273c7
--- /dev/null
+++ b/llvm/test/Instrumentation/RealtimeSanitizer/rtsan.ll
@@ -0,0 +1,35 @@
+; RUN: opt < %s -passes=rtsan -S | FileCheck %s
+
+; Function Attrs: mustprogress noinline nonblocking optnone ssp uwtable(sync)
+define void @violation() #0 {
+ %1 = alloca ptr, align 8
+ %2 = call ptr @malloc(i64 noundef 2) #3
+ store ptr %2, ptr %1, align 8
+ ret void
+}
+
+; Function Attrs: allocsize(0)
+declare ptr @malloc(i64 noundef) #1
+
+; Function Attrs: mustprogress noinline norecurse optnone ssp uwtable(sync)
+define noundef i32 @main() #2 {
+ %1 = alloca i32, align 4
+ store i32 0, ptr %1, align 4
+ call void @violation() #4
+ ret i32 0
+}
+
+attributes #0 = { mustprogress noinline nonblocking optnone ssp uwtable(sync) }
+attributes #1 = { allocsize(0) }
+attributes #2 = { mustprogress noinline norecurse optnone ssp uwtable(sync) }
+attributes #3 = { allocsize(0) }
+attributes #4 = { nonblocking }
+
+; RealtimeSanitizer pass should insert __rtsan_realtime_enter right after function definition
+; CHECK: define{{.*}}violation
+; CHECK-NEXT: call{{.*}}__rtsan_realtime_enter
+
+; RealtimeSanitizer pass should insert __rtsan_realtime_exit right before function return
+; CHECK: call{{.*}}@__rtsan_realtime_exit
+; CHECK-NEXT: ret{{.*}}void
+
|
@llvm/pr-subscribers-llvm-ir Author: Chris Apple (cjappl) ChangesAdd the RealtimeSanitizer pass to llvm. This also required adding a new "nonblocking" attribute, which will correspond to the nonblocking function effect in clang. Please see the reviewer support document for what our next steps are. The original discourse thread can be found here Full diff: https://github.com/llvm/llvm-project/pull/100596.diff 15 Files Affected:
diff --git a/llvm/CODE_OWNERS.TXT b/llvm/CODE_OWNERS.TXT
index d1620d1cbf870..c996cae8f97c5 100644
--- a/llvm/CODE_OWNERS.TXT
+++ b/llvm/CODE_OWNERS.TXT
@@ -263,3 +263,7 @@ D: C-SKY backend (lib/Target/CSKY/*)
N: Ilia Diachkov
E: [email protected]
D: SPIR-V backend (lib/Target/SPIRV/*)
+
+N: Christopher Apple, David Trevelyan
+E: [email protected], [email protected]
+D: RealtimeSanitizer (LLVM part)
diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
index fb88f2fe75adb..61b046c26a97f 100644
--- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h
+++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
@@ -758,6 +758,7 @@ enum AttributeKindCodes {
ATTR_KIND_SANITIZE_NUMERICAL_STABILITY = 93,
ATTR_KIND_INITIALIZES = 94,
ATTR_KIND_HYBRID_PATCHABLE = 95,
+ ATTR_KIND_NONBLOCKING = 96,
};
enum ComdatSelectionKindCodes {
diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td
index e1bd193891c1e..8d90e912f279c 100644
--- a/llvm/include/llvm/IR/Attributes.td
+++ b/llvm/include/llvm/IR/Attributes.td
@@ -239,6 +239,9 @@ def ReadNone : EnumAttr<"readnone", [ParamAttr]>;
/// Function only reads from memory.
def ReadOnly : EnumAttr<"readonly", [ParamAttr]>;
+/// Function is marked to be non-blocking
+def NonBlocking : EnumAttr<"nonblocking", [FnAttr]>;
+
/// Return value is always equal to this argument.
def Returned : EnumAttr<"returned", [ParamAttr]>;
diff --git a/llvm/include/llvm/Transforms/Instrumentation/RealtimeSanitizer.h b/llvm/include/llvm/Transforms/Instrumentation/RealtimeSanitizer.h
new file mode 100644
index 0000000000000..9cf2448361608
--- /dev/null
+++ b/llvm/include/llvm/Transforms/Instrumentation/RealtimeSanitizer.h
@@ -0,0 +1,35 @@
+//===--------- Definition of the RealtimeSanitizer class ---------*- C++
+//-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_TRANSFORMS_INSTRUMENTATION_REALTIMESANITIZER_H
+#define LLVM_TRANSFORMS_INSTRUMENTATION_REALTIMESANITIZER_H
+
+#include "llvm/IR/PassManager.h"
+#include "llvm/Transforms/Instrumentation/RealtimeSanitizerOptions.h"
+
+namespace llvm {
+
+struct RealtimeSanitizerOptions {};
+
+class RealtimeSanitizerPass : public PassInfoMixin<RealtimeSanitizerPass> {
+public:
+ RealtimeSanitizerPass(const RealtimeSanitizerOptions &Options);
+ PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM);
+
+ static bool isRequired() { return true; }
+
+private:
+ RealtimeSanitizerOptions Options{};
+};
+
+} // namespace llvm
+
+#endif // LLVM_TRANSFORMS_INSTRUMENTATION_REALTIMESANITIZER_H
diff --git a/llvm/include/llvm/Transforms/Instrumentation/RealtimeSanitizerOptions.h b/llvm/include/llvm/Transforms/Instrumentation/RealtimeSanitizerOptions.h
new file mode 100644
index 0000000000000..35376a5647c60
--- /dev/null
+++ b/llvm/include/llvm/Transforms/Instrumentation/RealtimeSanitizerOptions.h
@@ -0,0 +1,17 @@
+//===--------- Definition of the RealtimeSanitizer options -------*- C++
+//-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// This file defines data types used to set Realtime Sanitizer options.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TRANSFORMS_INSTRUMENTATION_REALTIMESANITIZEROPTIONS_H
+#define LLVM_TRANSFORMS_INSTRUMENTATION_REALTIMESANITIZEROPTIONS_H
+
+namespace llvm {} // namespace llvm
+
+#endif
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index 84d624f6cf8fa..a519748bc1c83 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -2109,6 +2109,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
return Attribute::ReadOnly;
case bitc::ATTR_KIND_RETURNED:
return Attribute::Returned;
+ case bitc::ATTR_KIND_NONBLOCKING:
+ return Attribute::NonBlocking;
case bitc::ATTR_KIND_RETURNS_TWICE:
return Attribute::ReturnsTwice;
case bitc::ATTR_KIND_S_EXT:
diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index 324dcbca8137e..d54aeae74a59f 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -805,6 +805,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
return bitc::ATTR_KIND_OPTIMIZE_FOR_SIZE;
case Attribute::OptimizeNone:
return bitc::ATTR_KIND_OPTIMIZE_NONE;
+ case Attribute::NonBlocking:
+ return bitc::ATTR_KIND_NONBLOCKING;
case Attribute::ReadNone:
return bitc::ATTR_KIND_READ_NONE;
case Attribute::ReadOnly:
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index 5dbb1e2f49871..faf3e25cb31d9 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -198,6 +198,7 @@
#include "llvm/Transforms/Instrumentation/PGOForceFunctionAttrs.h"
#include "llvm/Transforms/Instrumentation/PGOInstrumentation.h"
#include "llvm/Transforms/Instrumentation/PoisonChecking.h"
+#include "llvm/Transforms/Instrumentation/RealtimeSanitizer.h"
#include "llvm/Transforms/Instrumentation/SanitizerBinaryMetadata.h"
#include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
@@ -1207,6 +1208,11 @@ parseRegAllocFastPassOptions(PassBuilder &PB, StringRef Params) {
return Opts;
}
+Expected<RealtimeSanitizerOptions> parseRtSanPassOptions(StringRef Params) {
+ RealtimeSanitizerOptions Result;
+ return Result;
+}
+
} // namespace
/// Tests whether a pass name starts with a valid prefix for a default pipeline
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index 3b92823cd283b..f795c7242f958 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -590,6 +590,10 @@ FUNCTION_PASS_WITH_PARAMS(
return WinEHPreparePass(DemoteCatchSwitchPHIOnly);
},
parseWinEHPrepareOptions, "demote-catchswitch-only")
+FUNCTION_PASS_WITH_PARAMS(
+ "rtsan", "RealtimeSanitizerPass",
+ [](RealtimeSanitizerOptions Opts) { return RealtimeSanitizerPass(Opts); },
+ parseRtSanPassOptions, "")
#undef FUNCTION_PASS_WITH_PARAMS
#ifndef LOOPNEST_PASS
diff --git a/llvm/lib/Transforms/Instrumentation/CMakeLists.txt b/llvm/lib/Transforms/Instrumentation/CMakeLists.txt
index 4e3f9e27e0c34..deab37801ff1d 100644
--- a/llvm/lib/Transforms/Instrumentation/CMakeLists.txt
+++ b/llvm/lib/Transforms/Instrumentation/CMakeLists.txt
@@ -25,6 +25,7 @@ add_llvm_component_library(LLVMInstrumentation
ValueProfileCollector.cpp
ThreadSanitizer.cpp
HWAddressSanitizer.cpp
+ RealtimeSanitizer.cpp
ADDITIONAL_HEADER_DIRS
${LLVM_MAIN_INCLUDE_DIR}/llvm/Transforms
diff --git a/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
new file mode 100644
index 0000000000000..2fa2389c4984f
--- /dev/null
+++ b/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
@@ -0,0 +1,50 @@
+#include "llvm/IR/Analysis.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/Module.h"
+
+#include "llvm/Transforms/Instrumentation/RealtimeSanitizer.h"
+
+using namespace llvm;
+
+namespace {
+
+void insertCallBeforeInstruction(Function &Fn, Instruction &Instruction,
+ const char *FunctionName) {
+ LLVMContext &Context = Fn.getContext();
+ FunctionType *FuncType = FunctionType::get(Type::getVoidTy(Context), false);
+ FunctionCallee Func =
+ Fn.getParent()->getOrInsertFunction(FunctionName, FuncType);
+ IRBuilder<> Builder{&Instruction};
+ Builder.CreateCall(Func, {});
+}
+
+void insertCallAtFunctionEntryPoint(Function &Fn, const char *InsertFnName) {
+
+ insertCallBeforeInstruction(Fn, Fn.front().front(), InsertFnName);
+}
+
+void insertCallAtAllFunctionExitPoints(Function &Fn, const char *InsertFnName) {
+ for (auto &BB : Fn) {
+ for (auto &I : BB) {
+ if (auto *RI = dyn_cast<ReturnInst>(&I)) {
+ insertCallBeforeInstruction(Fn, I, InsertFnName);
+ }
+ }
+ }
+}
+} // namespace
+
+RealtimeSanitizerPass::RealtimeSanitizerPass(
+ const RealtimeSanitizerOptions &Options)
+ : Options{Options} {}
+
+PreservedAnalyses RealtimeSanitizerPass::run(Function &F,
+ AnalysisManager<Function> &AM) {
+ if (F.hasFnAttribute(Attribute::NonBlocking)) {
+ insertCallAtFunctionEntryPoint(F, "__rtsan_realtime_enter");
+ insertCallAtAllFunctionExitPoints(F, "__rtsan_realtime_exit");
+ return PreservedAnalyses::none();
+ }
+
+ return PreservedAnalyses::all();
+}
diff --git a/llvm/lib/Transforms/Utils/CodeExtractor.cpp b/llvm/lib/Transforms/Utils/CodeExtractor.cpp
index 5bca5cf8ff91f..1339bbb3842d4 100644
--- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp
+++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp
@@ -946,6 +946,7 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs,
case Attribute::NoUnwind:
case Attribute::NoSanitizeBounds:
case Attribute::NoSanitizeCoverage:
+ case Attribute::NonBlocking:
case Attribute::NullPointerIsValid:
case Attribute::OptimizeForDebugging:
case Attribute::OptForFuzzing:
diff --git a/llvm/test/Bitcode/attributes.ll b/llvm/test/Bitcode/attributes.ll
index f4dc9b9849827..5f8617dad8dfd 100644
--- a/llvm/test/Bitcode/attributes.ll
+++ b/llvm/test/Bitcode/attributes.ll
@@ -505,6 +505,12 @@ define void @f86() nosanitize_bounds
ret void;
}
+; CHECK: define void @f92() #53
+define void @f92() nonblocking
+{
+ ret void;
+}
+
; CHECK: define void @f87() [[FNRETTHUNKEXTERN:#[0-9]+]]
define void @f87() fn_ret_thunk_extern { ret void }
@@ -599,6 +605,7 @@ define void @initializes(ptr initializes((-4, 0), (4, 8)) %a) {
; CHECK: attributes #50 = { disable_sanitizer_instrumentation }
; CHECK: attributes #51 = { uwtable(sync) }
; CHECK: attributes #52 = { nosanitize_bounds }
+; CHECK: attributes #53 = { nonblocking }
; CHECK: attributes [[FNRETTHUNKEXTERN]] = { fn_ret_thunk_extern }
; CHECK: attributes [[SKIPPROFILE]] = { skipprofile }
; CHECK: attributes [[OPTDEBUG]] = { optdebug }
diff --git a/llvm/test/Bitcode/compatibility.ll b/llvm/test/Bitcode/compatibility.ll
index e437c37d8d1c8..1471138b91a9f 100644
--- a/llvm/test/Bitcode/compatibility.ll
+++ b/llvm/test/Bitcode/compatibility.ll
@@ -1564,7 +1564,7 @@ exit:
; CHECK: select <2 x i1> <i1 true, i1 false>, <2 x i8> <i8 2, i8 3>, <2 x i8> <i8 3, i8 2>
call void @f.nobuiltin() builtin
- ; CHECK: call void @f.nobuiltin() #52
+ ; CHECK: call void @f.nobuiltin() #53
call fastcc noalias ptr @f.noalias() noinline
; CHECK: call fastcc noalias ptr @f.noalias() #12
@@ -1991,6 +1991,9 @@ declare void @f.allockind() allockind("alloc,uninitialized")
declare void @f.sanitize_numerical_stability() sanitize_numerical_stability
; CHECK: declare void @f.sanitize_numerical_stability() #51
+declare void @f.nonblocking() nonblocking
+; CHECK: declare void @f.nonblocking() #52
+
; CHECK: declare nofpclass(snan) float @nofpclass_snan(float nofpclass(snan))
declare nofpclass(snan) float @nofpclass_snan(float nofpclass(snan))
@@ -2113,7 +2116,8 @@ define float @nofpclass_callsites(float %arg) {
; CHECK: attributes #49 = { nosanitize_bounds }
; CHECK: attributes #50 = { allockind("alloc,uninitialized") }
; CHECK: attributes #51 = { sanitize_numerical_stability }
-; CHECK: attributes #52 = { builtin }
+; CHECK: attributes #52 = { nonblocking }
+; CHECK: attributes #53 = { builtin }
;; Metadata
diff --git a/llvm/test/Instrumentation/RealtimeSanitizer/rtsan.ll b/llvm/test/Instrumentation/RealtimeSanitizer/rtsan.ll
new file mode 100644
index 0000000000000..222df484273c7
--- /dev/null
+++ b/llvm/test/Instrumentation/RealtimeSanitizer/rtsan.ll
@@ -0,0 +1,35 @@
+; RUN: opt < %s -passes=rtsan -S | FileCheck %s
+
+; Function Attrs: mustprogress noinline nonblocking optnone ssp uwtable(sync)
+define void @violation() #0 {
+ %1 = alloca ptr, align 8
+ %2 = call ptr @malloc(i64 noundef 2) #3
+ store ptr %2, ptr %1, align 8
+ ret void
+}
+
+; Function Attrs: allocsize(0)
+declare ptr @malloc(i64 noundef) #1
+
+; Function Attrs: mustprogress noinline norecurse optnone ssp uwtable(sync)
+define noundef i32 @main() #2 {
+ %1 = alloca i32, align 4
+ store i32 0, ptr %1, align 4
+ call void @violation() #4
+ ret i32 0
+}
+
+attributes #0 = { mustprogress noinline nonblocking optnone ssp uwtable(sync) }
+attributes #1 = { allocsize(0) }
+attributes #2 = { mustprogress noinline norecurse optnone ssp uwtable(sync) }
+attributes #3 = { allocsize(0) }
+attributes #4 = { nonblocking }
+
+; RealtimeSanitizer pass should insert __rtsan_realtime_enter right after function definition
+; CHECK: define{{.*}}violation
+; CHECK-NEXT: call{{.*}}__rtsan_realtime_enter
+
+; RealtimeSanitizer pass should insert __rtsan_realtime_exit right before function return
+; CHECK: call{{.*}}@__rtsan_realtime_exit
+; CHECK-NEXT: ret{{.*}}void
+
|
CC for review @vitalybuka @MaskRay @Sirraide @AaronBallman (maybe you can help suggest if someone is more appropriate in LLVM, this is my first PR in this area) Co-author @davidtrevelyan |
llvm/include/llvm/Transforms/Instrumentation/RealtimeSanitizer.h
Outdated
Show resolved
Hide resolved
llvm/include/llvm/Transforms/Instrumentation/RealtimeSanitizerOptions.h
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM but better to move transforms and CODE_OWNERS into separate patches
I have updated the review, splitting it into three:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing LangRef specification.
Can't say for sure without seeing the spec, but this is almost certainly the wrong name for the attribute. |
This name was chosen to match the name of the function effect it keys off of. This sanitizer works hand in hand with clang "function effects" that look like Eventually we will add LLVM IR attributes for A "reviewers guide" can be found here, describing how the sanitizer works: We will defer to people more experienced in LLVM what the appropriate choice is here! EDIT: Posed this as a question in the discourse thread https://discourse.llvm.org/t/rfc-nolock-and-noalloc-attributes/76837/103?u=cjappl |
Fixed in latest version! Thanks for catching |
@nikic based on your suggestions, I decided to update this to the attribute |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@nikic or @vitalybuka could we get a merge on this when you get a chance? Thanks for everyone's review and discussion! |
Split from #100596. Introduce the RealtimeSanitizer transform, which inserts the rtsan_enter/exit functions at the appropriate places in an instrumented function.
Add a new "sanitize_realtime" attribute, which will correspond to the sanitize_realtime function effect in clang. This is used in the realtime sanitizer transform
Please see the reviewer support document for what our next steps are. The original discourse thread can be found here