https://github.com/jdoerfert updated 
https://github.com/llvm/llvm-project/pull/196234

>From 42f99d61f246b65f5253e10b2b118c62406b174b Mon Sep 17 00:00:00 2001
From: Johannes Doerfert <[email protected]>
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      | 22 ++++++-
 .../Instrumentor/default_config.json          |  4 +-
 .../Instrumentor/function_regex.json          | 26 +++++++++
 .../Instrumentor/function_regex.ll            | 57 +++++++++++++++++++
 5 files changed, 113 insertions(+), 4 deletions(-)
 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 796104944f7a1..63a37931e98dc 100644
--- a/llvm/include/llvm/Transforms/IPO/Instrumentor.h
+++ b/llvm/include/llvm/Transforms/IPO/Instrumentor.h
@@ -356,7 +356,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",
@@ -423,6 +428,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 e42befada5ab2..23fbeb9e7ec33 100644
--- a/llvm/lib/Transforms/IPO/Instrumentor.cpp
+++ b/llvm/lib/Transforms/IPO/Instrumentor.cpp
@@ -158,6 +158,9 @@ class InstrumentorImpl final {
   /// The instrumentor configuration.
   InstrumentationConfig &IConf;
 
+  /// The function regex filter, if any.
+  Regex ParsedFunctionRegex;
+
   /// The underlying module.
   Module &M;
 
@@ -175,7 +178,7 @@ bool InstrumentorImpl::shouldInstrumentTarget() {
   bool RegexMatches = true;
   const auto 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(
@@ -194,7 +197,11 @@ bool InstrumentorImpl::shouldInstrumentTarget() {
 bool InstrumentorImpl::shouldInstrumentFunction(Function &Fn) {
   if (Fn.isDeclaration())
     return false;
-  return !Fn.getName().starts_with(IConf.getRTName()) ||
+  bool RegexMatches = true;
+  const auto FunctionRegexStr = IConf.FunctionRegex->getString();
+  if (!FunctionRegexStr.empty())
+    RegexMatches = ParsedFunctionRegex.match(Fn.getName());
+  return (RegexMatches && !Fn.getName().starts_with(IConf.getRTName())) ||
          Fn.hasFnAttribute("instrument");
 }
 
@@ -279,6 +286,17 @@ bool InstrumentorImpl::instrument() {
   if (!shouldInstrumentTarget())
     return Changed;
 
+  const auto 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_Warning));
+      return false;
+    }
+  }
+
   for (auto &[Name, IO] :
        IConf.IChoices[InstrumentationLocation::INSTRUCTION_PRE])
     if (IO->Enabled)
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
+}

_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to