[llvm-branch-commits] [llvm] [Instrumentor] Add a global function regexp to limit the instrumentation (PR #196234)
Johannes Doerfert via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Mon May 11 19:13:56 PDT 2026
https://github.com/jdoerfert updated https://github.com/llvm/llvm-project/pull/196234
>From 18edc05fa09fe3103a691056f826cea860185736 Mon Sep 17 00:00:00 2001
From: Johannes Doerfert <jdoerfert.llvm at gmail.com>
Date: Mon, 4 May 2026 15:19:00 -0700
Subject: [PATCH] [Instrumentor] Add a global function regexp to limit the
instrumentation
Only functions that match the "function_regex" will be instrumented,
or if they have the instrumentation attribute.
---
.../llvm/Transforms/IPO/Instrumentor.h | 8 ++-
llvm/lib/Transforms/IPO/Instrumentor.cpp | 26 +++++++--
.../Instrumentor/bad_function_regex.json | 26 +++++++++
.../Instrumentor/bad_function_regexp.ll | 13 +++++
.../Instrumentor/default_config.json | 4 +-
.../Instrumentor/function_regex.json | 26 +++++++++
.../Instrumentor/function_regex.ll | 57 +++++++++++++++++++
7 files changed, 154 insertions(+), 6 deletions(-)
create mode 100644 llvm/test/Instrumentation/Instrumentor/bad_function_regex.json
create mode 100644 llvm/test/Instrumentation/Instrumentor/bad_function_regexp.ll
create mode 100644 llvm/test/Instrumentation/Instrumentor/function_regex.json
create mode 100644 llvm/test/Instrumentation/Instrumentor/function_regex.ll
diff --git a/llvm/include/llvm/Transforms/IPO/Instrumentor.h b/llvm/include/llvm/Transforms/IPO/Instrumentor.h
index 747c3d110b650..ba3ad2498c873 100644
--- a/llvm/include/llvm/Transforms/IPO/Instrumentor.h
+++ b/llvm/include/llvm/Transforms/IPO/Instrumentor.h
@@ -357,7 +357,12 @@ struct InstrumentationConfig {
TargetRegex = BaseConfigurationOption::createStringOption(
*this, "target_regex",
"Regular expression to be matched against the module target. "
- "Only targets that match this regex will be instrumented",
+ "Only targets that match this regex will be instrumented.",
+ "");
+ FunctionRegex = BaseConfigurationOption::createStringOption(
+ *this, "function_regex",
+ "Regular expression to be matched against a function name. "
+ "Only functions that match this regex will be instrumented.",
"");
DemangleFunctionNames = BaseConfigurationOption::createBoolOption(
*this, "demangle_function_names",
@@ -424,6 +429,7 @@ struct InstrumentationConfig {
std::unique_ptr<BaseConfigurationOption> RuntimeStubsFile;
std::unique_ptr<BaseConfigurationOption> DemangleFunctionNames;
std::unique_ptr<BaseConfigurationOption> TargetRegex;
+ std::unique_ptr<BaseConfigurationOption> FunctionRegex;
std::unique_ptr<BaseConfigurationOption> HostEnabled;
std::unique_ptr<BaseConfigurationOption> GPUEnabled;
diff --git a/llvm/lib/Transforms/IPO/Instrumentor.cpp b/llvm/lib/Transforms/IPO/Instrumentor.cpp
index bffc84f1d35e4..3862bfbbee9fa 100644
--- a/llvm/lib/Transforms/IPO/Instrumentor.cpp
+++ b/llvm/lib/Transforms/IPO/Instrumentor.cpp
@@ -161,6 +161,9 @@ class InstrumentorImpl final {
/// The instrumentor configuration.
InstrumentationConfig &IConf;
+ /// The function regex filter, if any.
+ Regex ParsedFunctionRegex;
+
/// The underlying module.
Module &M;
@@ -176,13 +179,13 @@ bool InstrumentorImpl::shouldInstrumentTarget() {
const bool IsGPU = T.isAMDGPU() || T.isNVPTX();
bool RegexMatches = true;
- const auto TargetRegexStr = IConf.TargetRegex->getString();
+ StringRef TargetRegexStr = IConf.TargetRegex->getString();
if (!TargetRegexStr.empty()) {
- llvm::Regex TargetRegex(TargetRegexStr);
+ Regex TargetRegex(TargetRegexStr);
std::string ErrMsg;
if (!TargetRegex.isValid(ErrMsg)) {
IIRB.Ctx.diagnose(DiagnosticInfoInstrumentation(
- Twine("failed to parse target regex: ") + ErrMsg, DS_Warning));
+ Twine("failed to parse target regex: ") + ErrMsg, DS_Error));
return false;
}
RegexMatches = TargetRegex.match(T.str());
@@ -197,7 +200,11 @@ bool InstrumentorImpl::shouldInstrumentTarget() {
bool InstrumentorImpl::shouldInstrumentFunction(Function &Fn) {
if (Fn.isDeclaration())
return false;
- return !Fn.getName().starts_with(IConf.getRTName()) ||
+ bool RegexMatches = true;
+ StringRef FunctionRegexStr = IConf.FunctionRegex->getString();
+ if (!FunctionRegexStr.empty())
+ RegexMatches = ParsedFunctionRegex.match(Fn.getName());
+ return (RegexMatches && !Fn.getName().starts_with(IConf.getRTName())) ||
Fn.hasFnAttribute("instrument");
}
@@ -282,6 +289,17 @@ bool InstrumentorImpl::instrument() {
if (!shouldInstrumentTarget())
return Changed;
+ StringRef FunctionRegexStr = IConf.FunctionRegex->getString();
+ if (!FunctionRegexStr.empty()) {
+ ParsedFunctionRegex = Regex(FunctionRegexStr);
+ std::string ErrMsg;
+ if (!ParsedFunctionRegex.isValid(ErrMsg)) {
+ IIRB.Ctx.diagnose(DiagnosticInfoInstrumentation(
+ Twine("failed to parse target regex: ") + ErrMsg, DS_Error));
+ return false;
+ }
+ }
+
for (auto &[Name, IO] :
IConf.IChoices[InstrumentationLocation::INSTRUCTION_PRE])
if (IO->Enabled)
diff --git a/llvm/test/Instrumentation/Instrumentor/bad_function_regex.json b/llvm/test/Instrumentation/Instrumentor/bad_function_regex.json
new file mode 100644
index 0000000000000..f60a5a874fa5e
--- /dev/null
+++ b/llvm/test/Instrumentation/Instrumentor/bad_function_regex.json
@@ -0,0 +1,26 @@
+{
+ "configuration": {
+ "runtime_prefix": "__instrumentor_",
+ "function_regex": "**!%*@*"
+ },
+ "instruction_pre": {
+ "load": {
+ "enabled": true,
+ "id": true
+ },
+ "store": {
+ "enabled": true,
+ "id": false
+ }
+ },
+ "instruction_post": {
+ "load": {
+ "enabled": true,
+ "id": true
+ },
+ "store": {
+ "enabled": true,
+ "id": true
+ }
+ }
+}
diff --git a/llvm/test/Instrumentation/Instrumentor/bad_function_regexp.ll b/llvm/test/Instrumentation/Instrumentor/bad_function_regexp.ll
new file mode 100644
index 0000000000000..8ee73531a3d69
--- /dev/null
+++ b/llvm/test/Instrumentation/Instrumentor/bad_function_regexp.ll
@@ -0,0 +1,13 @@
+; RUN: not opt < %s -passes=instrumentor -instrumentor-read-config-file=%S/bad_function_regex.json -S 2>&1 | FileCheck %s
+
+; CHECK: error: failed to parse target regex: repetition-operator operand invalid
+
+target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+
+define i32 @foo() {
+entry:
+ %0 = alloca i32, align 4
+ store i32 0, ptr %0, align 4
+ %2 = load i32, ptr %0, align 4
+ ret i32 %2
+}
diff --git a/llvm/test/Instrumentation/Instrumentor/default_config.json b/llvm/test/Instrumentation/Instrumentor/default_config.json
index 01dd8f8a8f720..c97701d4d84c5 100644
--- a/llvm/test/Instrumentation/Instrumentor/default_config.json
+++ b/llvm/test/Instrumentation/Instrumentor/default_config.json
@@ -5,7 +5,9 @@
"runtime_stubs_file": "",
"runtime_stubs_file.description": "The file into which runtime stubs should be written.",
"target_regex": "",
- "target_regex.description": "Regular expression to be matched against the module target. Only targets that match this regex will be instrumented",
+ "target_regex.description": "Regular expression to be matched against the module target. Only targets that match this regex will be instrumented.",
+ "function_regex": "",
+ "function_regex.description": "Regular expression to be matched against a function name. Only functions that match this regex will be instrumented.",
"demangle_function_names": true,
"demangle_function_names.description": "Demangle functions names passed to the runtime.",
"host_enabled": true,
diff --git a/llvm/test/Instrumentation/Instrumentor/function_regex.json b/llvm/test/Instrumentation/Instrumentor/function_regex.json
new file mode 100644
index 0000000000000..91435c73f0f20
--- /dev/null
+++ b/llvm/test/Instrumentation/Instrumentor/function_regex.json
@@ -0,0 +1,26 @@
+{
+ "configuration": {
+ "runtime_prefix": "__instrumentor_",
+ "function_regex": "foo|baz"
+ },
+ "instruction_pre": {
+ "load": {
+ "enabled": true,
+ "id": true
+ },
+ "store": {
+ "enabled": true,
+ "id": false
+ }
+ },
+ "instruction_post": {
+ "load": {
+ "enabled": true,
+ "id": true
+ },
+ "store": {
+ "enabled": true,
+ "id": true
+ }
+ }
+}
diff --git a/llvm/test/Instrumentation/Instrumentor/function_regex.ll b/llvm/test/Instrumentation/Instrumentor/function_regex.ll
new file mode 100644
index 0000000000000..29e28611aa114
--- /dev/null
+++ b/llvm/test/Instrumentation/Instrumentor/function_regex.ll
@@ -0,0 +1,57 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -passes=instrumentor -instrumentor-read-config-file=%S/function_regex.json -S | FileCheck %s
+
+target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+
+define i32 @foo() {
+; CHECK-LABEL: @foo(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[TMP0:%.*]] = alloca i32, align 4
+; CHECK-NEXT: call void @__instrumentor_pre_store() #[[ATTR0:[0-9]+]]
+; CHECK-NEXT: store i32 0, ptr [[TMP0]], align 4
+; CHECK-NEXT: call void @__instrumentor_post_store(i32 -1) #[[ATTR0]]
+; CHECK-NEXT: call void @__instrumentor_pre_load(i32 2) #[[ATTR0]]
+; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 4
+; CHECK-NEXT: call void @__instrumentor_post_load(i32 -2) #[[ATTR0]]
+; CHECK-NEXT: ret i32 [[TMP1]]
+;
+entry:
+ %0 = alloca i32, align 4
+ store i32 0, ptr %0, align 4
+ %2 = load i32, ptr %0, align 4
+ ret i32 %2
+}
+
+define i32 @bar() {
+; CHECK-LABEL: @bar(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[TMP0:%.*]] = alloca i32, align 4
+; CHECK-NEXT: store i32 0, ptr [[TMP0]], align 4
+; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 4
+; CHECK-NEXT: ret i32 [[TMP1]]
+;
+entry:
+ %0 = alloca i32, align 4
+ store i32 0, ptr %0, align 4
+ %2 = load i32, ptr %0, align 4
+ ret i32 %2
+}
+
+define i32 @baz() {
+; CHECK-LABEL: @baz(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[TMP0:%.*]] = alloca i32, align 4
+; CHECK-NEXT: call void @__instrumentor_pre_store() #[[ATTR0]]
+; CHECK-NEXT: store i32 0, ptr [[TMP0]], align 4
+; CHECK-NEXT: call void @__instrumentor_post_store(i32 -3) #[[ATTR0]]
+; CHECK-NEXT: call void @__instrumentor_pre_load(i32 4) #[[ATTR0]]
+; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 4
+; CHECK-NEXT: call void @__instrumentor_post_load(i32 -4) #[[ATTR0]]
+; CHECK-NEXT: ret i32 [[TMP1]]
+;
+entry:
+ %0 = alloca i32, align 4
+ store i32 0, ptr %0, align 4
+ %2 = load i32, ptr %0, align 4
+ ret i32 %2
+}
More information about the llvm-branch-commits
mailing list