[llvm] [Instrumentor] Add call instrumentation support (PR #206658)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Jun 29 23:56:39 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Jianjian Guan (jacquesguan)
<details>
<summary>Changes</summary>
---
Patch is 23.59 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/206658.diff
9 Files Affected:
- (modified) llvm/include/llvm/Transforms/IPO/Instrumentor.h (+62)
- (modified) llvm/lib/Transforms/IPO/Instrumentor.cpp (+115)
- (modified) llvm/lib/Transforms/IPO/InstrumentorUtils.cpp (+44-5)
- (modified) llvm/test/Instrumentation/Instrumentor/alloca_and_function.ll (+14-6)
- (added) llvm/test/Instrumentation/Instrumentor/call-config.json (+29)
- (added) llvm/test/Instrumentation/Instrumentor/call-name-filter-config.json (+20)
- (added) llvm/test/Instrumentation/Instrumentor/call-name-filter.ll (+29)
- (added) llvm/test/Instrumentation/Instrumentor/call.ll (+26)
- (modified) llvm/test/Instrumentation/Instrumentor/default_config.json (+45-1)
``````````diff
diff --git a/llvm/include/llvm/Transforms/IPO/Instrumentor.h b/llvm/include/llvm/Transforms/IPO/Instrumentor.h
index fceb9e58b9791..9f86f87151618 100644
--- a/llvm/include/llvm/Transforms/IPO/Instrumentor.h
+++ b/llvm/include/llvm/Transforms/IPO/Instrumentor.h
@@ -1110,6 +1110,68 @@ struct LoadIO : public InstructionIO<Instruction::Load> {
}
};
+/// The instrumentation opportunity for call instructions.
+struct CallIO final : public InstructionIO<Instruction::Call> {
+ CallIO(InstrumentationLocation::KindTy Kind) : InstructionIO(Kind) {}
+
+ enum ConfigKind {
+ PassCallee = 0,
+ PassCalleeName,
+ PassNumArguments,
+ PassArguments,
+ PassReturnValue,
+ PassReturnValueSize,
+ PassReturnTypeId,
+ PassReturnSubTypeId,
+ PassId,
+ NumConfig,
+ };
+
+ using ConfigTy = BaseConfigTy<ConfigKind>;
+ ConfigTy Config;
+
+ StringRef getName() const override { return "call"; }
+
+ LLVM_ABI void init(InstrumentationConfig &IConf,
+ InstrumentorIRBuilderTy &IIRB,
+ ConfigTy *UserConfig = nullptr);
+
+ LLVM_ABI static Value *getCallee(Value &V, Type &Ty,
+ InstrumentationConfig &IConf,
+ InstrumentorIRBuilderTy &IIRB);
+ LLVM_ABI static Value *getCalleeName(Value &V, Type &Ty,
+ InstrumentationConfig &IConf,
+ InstrumentorIRBuilderTy &IIRB);
+ LLVM_ABI static Value *getNumArguments(Value &V, Type &Ty,
+ InstrumentationConfig &IConf,
+ InstrumentorIRBuilderTy &IIRB);
+ LLVM_ABI static Value *getArguments(Value &V, Type &Ty,
+ InstrumentationConfig &IConf,
+ InstrumentorIRBuilderTy &IIRB);
+ LLVM_ABI static Value *getReturnValue(Value &V, Type &Ty,
+ InstrumentationConfig &IConf,
+ InstrumentorIRBuilderTy &IIRB);
+ LLVM_ABI static Value *getReturnValueSize(Value &V, Type &Ty,
+ InstrumentationConfig &IConf,
+ InstrumentorIRBuilderTy &IIRB);
+ LLVM_ABI static Value *getReturnTypeId(Value &V, Type &Ty,
+ InstrumentationConfig &IConf,
+ InstrumentorIRBuilderTy &IIRB);
+ LLVM_ABI static Value *getReturnSubTypeId(Value &V, Type &Ty,
+ InstrumentationConfig &IConf,
+ InstrumentorIRBuilderTy &IIRB);
+
+ static void populate(InstrumentationConfig &IConf,
+ InstrumentorIRBuilderTy &IIRB) {
+ auto *PreIO =
+ IConf.allocate<CallIO>(InstrumentationLocation::INSTRUCTION_PRE);
+ PreIO->init(IConf, IIRB);
+ auto *PostIO =
+ IConf.allocate<CallIO>(InstrumentationLocation::INSTRUCTION_POST);
+ PostIO->init(IConf, IIRB);
+ }
+};
+
/// The instrumentation opportunity for type cast instructions.
/// This includes PtrToInt, IntToPtr, Trunc, ZExt, SExt, FPToUI, FPToSI,
/// UIToFP, SIToFP, FPTrunc, FPExt, AddrSpaceCast, and BitCast.
diff --git a/llvm/lib/Transforms/IPO/Instrumentor.cpp b/llvm/lib/Transforms/IPO/Instrumentor.cpp
index 3b52e3e1f4605..65cdbd0ea418d 100644
--- a/llvm/lib/Transforms/IPO/Instrumentor.cpp
+++ b/llvm/lib/Transforms/IPO/Instrumentor.cpp
@@ -568,6 +568,7 @@ void InstrumentationConfig::populate(InstrumentorIRBuilderTy &IIRB) {
UnreachableIO::populate(*this, IIRB);
LoadIO::populate(*this, IIRB);
StoreIO::populate(*this, IIRB);
+ CallIO::populate(*this, IIRB);
CastIO::populate(*this, IIRB);
NumericIO::populate(*this, IIRB);
CompareIO::populate(*this, IIRB);
@@ -1435,6 +1436,120 @@ Value *LoadIO::isVolatile(Value &V, Type &Ty, InstrumentationConfig &IConf,
return getCI(&Ty, LI.isVolatile());
}
+void CallIO::init(InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB,
+ ConfigTy *UserConfig) {
+ if (UserConfig)
+ Config = *UserConfig;
+
+ bool IsPRE = getLocationKind() == InstrumentationLocation::INSTRUCTION_PRE;
+ if (Config.has(PassCallee)) {
+ IRTArgs.push_back(IRTArg(IIRB.PtrTy, "callee",
+ "The called function pointer.", IRTArg::NONE,
+ getCallee));
+ }
+ if (Config.has(PassCalleeName)) {
+ IRTArgs.push_back(IRTArg(IIRB.PtrTy, "callee_name",
+ "The called function name.", IRTArg::STRING,
+ getCalleeName));
+ }
+ if (Config.has(PassNumArguments)) {
+ IRTArgs.push_back(IRTArg(IIRB.Int32Ty, "num_arguments",
+ "Number of call arguments.", IRTArg::NONE,
+ getNumArguments));
+ }
+ if (Config.has(PassArguments)) {
+ IRTArgs.push_back(IRTArg(IIRB.PtrTy, "arguments",
+ "Description of the call arguments.",
+ IRTArg::VALUE_PACK, getArguments));
+ }
+ if (!IsPRE && Config.has(PassReturnValue)) {
+ IRTArgs.push_back(
+ IRTArg(IIRB.Int64Ty, "return_value", "The call return value.",
+ IRTArg::POTENTIALLY_INDIRECT |
+ (Config.has(PassReturnValueSize) ? IRTArg::INDIRECT_HAS_SIZE
+ : IRTArg::NONE),
+ getReturnValue));
+ }
+ if (Config.has(PassReturnValueSize)) {
+ IRTArgs.push_back(IRTArg(IIRB.Int64Ty, "return_value_size",
+ "The size of the call return value.", IRTArg::NONE,
+ getReturnValueSize));
+ }
+ if (Config.has(PassReturnTypeId)) {
+ IRTArgs.push_back(IRTArg(IIRB.Int32Ty, "return_type_id",
+ "The type id of the call return value.",
+ IRTArg::TYPEID, getReturnTypeId));
+ }
+ if (Config.has(PassReturnSubTypeId)) {
+ IRTArgs.push_back(IRTArg(
+ IIRB.Int32Ty, "return_sub_type_id",
+ "The sub type id of the call return value (for arrays and vectors, or "
+ "-1).",
+ IRTArg::TYPEID, getReturnSubTypeId));
+ }
+
+ addCommonArgs(IConf, IIRB.Ctx, Config.has(PassId));
+ IConf.addChoice(*this, IIRB.Ctx);
+}
+
+Value *CallIO::getCallee(Value &V, Type &Ty, InstrumentationConfig &IConf,
+ InstrumentorIRBuilderTy &IIRB) {
+ auto &CI = cast<CallInst>(V);
+ return CI.getCalledOperand();
+}
+
+Value *CallIO::getCalleeName(Value &V, Type &Ty, InstrumentationConfig &IConf,
+ InstrumentorIRBuilderTy &IIRB) {
+ auto &CI = cast<CallInst>(V);
+ auto *Callee = CI.getCalledFunction();
+ if (!Callee)
+ return IConf.getGlobalString("", IIRB);
+ return IConf.getGlobalString(IConf.DemangleFunctionNames->getBool()
+ ? demangle(Callee->getName())
+ : Callee->getName(),
+ IIRB);
+}
+
+Value *CallIO::getNumArguments(Value &V, Type &Ty, InstrumentationConfig &IConf,
+ InstrumentorIRBuilderTy &IIRB) {
+ auto &CI = cast<CallInst>(V);
+ return getCI(&Ty, CI.arg_size());
+}
+
+Value *CallIO::getArguments(Value &V, Type &Ty, InstrumentationConfig &IConf,
+ InstrumentorIRBuilderTy &IIRB) {
+ auto &CI = cast<CallInst>(V);
+ return createValuePack(CI.args(), IConf, IIRB);
+}
+
+Value *CallIO::getReturnValue(Value &V, Type &Ty, InstrumentationConfig &IConf,
+ InstrumentorIRBuilderTy &IIRB) {
+ return &V;
+}
+
+Value *CallIO::getReturnValueSize(Value &V, Type &Ty,
+ InstrumentationConfig &IConf,
+ InstrumentorIRBuilderTy &IIRB) {
+ auto &CI = cast<CallInst>(V);
+ if (CI.getType()->isVoidTy())
+ return getCI(&Ty, 0);
+ auto &DL = CI.getDataLayout();
+ return getCI(&Ty, DL.getTypeStoreSize(CI.getType()));
+}
+
+Value *CallIO::getReturnTypeId(Value &V, Type &Ty, InstrumentationConfig &IConf,
+ InstrumentorIRBuilderTy &IIRB) {
+ auto &CI = cast<CallInst>(V);
+ return getCI(&Ty, CI.getType()->getTypeID());
+}
+
+Value *CallIO::getReturnSubTypeId(Value &V, Type &Ty,
+ InstrumentationConfig &IConf,
+ InstrumentorIRBuilderTy &IIRB) {
+ auto &CI = cast<CallInst>(V);
+ return getSubTypeID(*CI.getType(), Ty);
+}
+
void BasePointerIO::init(InstrumentationConfig &IConf,
InstrumentorIRBuilderTy &IIRB, ConfigTy *UserConfig) {
if (UserConfig)
diff --git a/llvm/lib/Transforms/IPO/InstrumentorUtils.cpp b/llvm/lib/Transforms/IPO/InstrumentorUtils.cpp
index 7030002824761..15fbacd813db0 100644
--- a/llvm/lib/Transforms/IPO/InstrumentorUtils.cpp
+++ b/llvm/lib/Transforms/IPO/InstrumentorUtils.cpp
@@ -20,6 +20,45 @@ using namespace llvm::instrumentor;
namespace {
enum PropertyType { INT, STRING, POINTER, UNKNOWN };
+static GlobalVariable *findGlobalString(Value *V, unsigned Depth = 0) {
+ if (Depth > 4)
+ return nullptr;
+
+ V = V->stripPointerCasts();
+ if (auto *GV = dyn_cast<GlobalVariable>(V))
+ return GV;
+
+ auto *C = dyn_cast<Constant>(V);
+ if (!C)
+ return nullptr;
+
+ for (Value *Op : C->operands())
+ if (auto *GV = findGlobalString(Op, Depth + 1))
+ return GV;
+ return nullptr;
+}
+
+static bool getConstantCString(Value *V, StringRef &S) {
+ auto *GV = findGlobalString(V);
+ if (!GV || !GV->isConstant() || !GV->hasInitializer())
+ return false;
+
+ if (isa<ConstantAggregateZero>(GV->getInitializer())) {
+ auto *AT = dyn_cast<ArrayType>(GV->getValueType());
+ if (AT && AT->getElementType()->isIntegerTy(8)) {
+ S = "";
+ return true;
+ }
+ }
+
+ auto *CDA = dyn_cast<ConstantDataArray>(GV->getInitializer());
+ if (!CDA || !CDA->isCString())
+ return false;
+
+ S = CDA->getAsCString();
+ return true;
+}
+
/// Simple filter expression evaluator for instrumentation opportunities.
/// Supports integer comparisons (==, !=, <, >, <=, >=), string comparisons
/// (==, !=), pointer comparisons (==, !=) against null, string prefix checks
@@ -438,11 +477,11 @@ bool llvm::instrumentor::evaluateFilter(Value &V, bool &Changed,
IntPropertyValues[Arg.Name] = CI->getSExtValue();
} else if ((Arg.Flags & IRTArg::STRING) && isa<Constant>(ArgValue)) {
// Check for constant string values (marked with STRING flag).
- if (auto *GV = dyn_cast<GlobalVariable>(ArgValue))
- if (GV->isConstant() && GV->hasInitializer())
- if (auto *CDA = dyn_cast<ConstantDataArray>(GV->getInitializer()))
- if (CDA->isCString())
- StringPropertyValues[Arg.Name] = CDA->getAsCString();
+ StringRef S;
+ if (getConstantCString(ArgValue, S))
+ StringPropertyValues[Arg.Name] = S;
+ else
+ DynamicProperties[Arg.Name] = STRING;
} else if (ArgValue->getType()->isPointerTy()) {
// Check for pointer values (for null comparisons), after the strings.
PointerPropertyValues[Arg.Name] = ArgValue;
diff --git a/llvm/test/Instrumentation/Instrumentor/alloca_and_function.ll b/llvm/test/Instrumentation/Instrumentor/alloca_and_function.ll
index a2afecda64ebf..75eb8001a6d09 100644
--- a/llvm/test/Instrumentation/Instrumentor/alloca_and_function.ll
+++ b/llvm/test/Instrumentation/Instrumentor/alloca_and_function.ll
@@ -13,19 +13,22 @@ declare void @use(ptr)
; CHECK: @__instrumentor_.str = private unnamed_addr constant [8 x i8] c"<stdin>\00", align 1
; CHECK: @__instrumentor_.str.1 = private unnamed_addr constant [1 x i8] zeroinitializer, align 1
; CHECK: @llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 1000, ptr @__instrumentor_dtor, ptr null }]
-; CHECK: @__instrumentor_.str.2 = private unnamed_addr constant [4 x i8] c"foo\00", align 1
-; CHECK: @__instrumentor_value_pack = internal global <{ i32, i32, [6 x i8], i16, i32, i32, [4 x i8], float }> <{ i32 2, i32 12, [6 x i8] zeroinitializer, i16 0, i32 4, i32 2, [4 x i8] zeroinitializer, float 0.000000e+00 }>
+; CHECK: @__instrumentor_.str.2 = private unnamed_addr constant [4 x i8] c"use\00", align 1
+; CHECK: @__instrumentor_value_pack = internal global <{ i32, i32, ptr }> <{ i32 8, i32 15, ptr null }>
+; CHECK: @__instrumentor_.str.3 = private unnamed_addr constant [4 x i8] c"foo\00", align 1
+; CHECK: @__instrumentor_value_pack.4 = internal global <{ i32, i32, [6 x i8], i16, i32, i32, [4 x i8], float }> <{ i32 2, i32 12, [6 x i8] zeroinitializer, i16 0, i32 4, i32 2, [4 x i8] zeroinitializer, float 0.000000e+00 }>
define float @foo(i16 %a, float %b) {
; CHECK-LABEL: define float @foo(
; CHECK-SAME: i16 [[A:%.*]], float [[B:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[TMP0:%.*]] = alloca <{ i32, i32, [6 x i8], i16, i32, i32, [4 x i8], float }>, align 8
-; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[TMP0]], ptr @__instrumentor_value_pack, i64 32, i1 false)
+; CHECK-NEXT: [[CALL_ARGS:%.*]] = alloca <{ i32, i32, ptr }>, align 8
+; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[TMP0]], ptr @__instrumentor_value_pack.4, i64 32, i1 false)
; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds nuw <{ i32, i32, [6 x i8], i16, i32, i32, [4 x i8], float }>, ptr [[TMP0]], i32 0, i32 3
; CHECK-NEXT: store i16 [[A]], ptr [[TMP2]], align 2
; CHECK-NEXT: [[TMP14:%.*]] = getelementptr inbounds nuw <{ i32, i32, [6 x i8], i16, i32, i32, [4 x i8], float }>, ptr [[TMP0]], i32 0, i32 7
; CHECK-NEXT: store float [[B]], ptr [[TMP14]], align 4
-; CHECK-NEXT: call void @__instrumentor_pre_function(ptr @foo, ptr @__instrumentor_.str.2, i32 2, ptr [[TMP0]], i8 0, i32 5) #[[ATTR1:[0-9]+]]
+; CHECK-NEXT: call void @__instrumentor_pre_function(ptr @foo, ptr @__instrumentor_.str.3, i32 2, ptr [[TMP0]], i8 0, i32 6) #[[ATTR1:[0-9]+]]
; CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i32 14
; CHECK-NEXT: [[TMP4:%.*]] = load i16, ptr [[TMP3]], align 2
; CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i32 28
@@ -38,13 +41,18 @@ define float @foo(i16 %a, float %b) {
; CHECK-NEXT: [[TMP11:%.*]] = call ptr @__instrumentor_pre_store(ptr [[TMP9]], i32 0, ptr [[TMP15]], i64 [[TMP10]], i64 2, i64 2, i32 12, i32 -1, i32 0, i8 1, i8 0, i32 4) #[[ATTR1]]
; CHECK-NEXT: store i16 [[TMP4]], ptr [[TMP11]], align 2
; CHECK-NEXT: call void @__instrumentor_post_store(ptr [[TMP9]], i32 0, ptr [[TMP15]], i64 [[TMP10]], i64 2, i64 2, i32 12, i32 -1, i32 0, i8 1, i8 0, i32 -4) #[[ATTR1]]
+; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[CALL_ARGS]], ptr @__instrumentor_value_pack, i64 16, i1 false)
+; CHECK-NEXT: [[CALL_ARG_PTR:%.*]] = getelementptr inbounds nuw <{ i32, i32, ptr }>, ptr [[CALL_ARGS]], i32 0, i32 2
+; CHECK-NEXT: store ptr [[TMP9]], ptr [[CALL_ARG_PTR]], align 8
+; CHECK-NEXT: call void @__instrumentor_pre_call(ptr @use, ptr @__instrumentor_.str.2, i32 1, ptr [[CALL_ARGS]], i64 0, i32 7, i32 -1, i32 5) #[[ATTR1]]
; CHECK-NEXT: call void @use(ptr [[TMP9]])
-; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[TMP0]], ptr @__instrumentor_value_pack, i64 32, i1 false)
+; CHECK-NEXT: call void @__instrumentor_post_call(ptr @use, ptr @__instrumentor_.str.2, i32 1, ptr [[CALL_ARGS]], i64 0, i64 0, i32 7, i32 -1, i32 -5) #[[ATTR1]]
+; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[TMP0]], ptr @__instrumentor_value_pack.4, i64 32, i1 false)
; CHECK-NEXT: [[TMP12:%.*]] = getelementptr inbounds nuw <{ i32, i32, [6 x i8], i16, i32, i32, [4 x i8], float }>, ptr [[TMP0]], i32 0, i32 3
; CHECK-NEXT: store i16 [[A]], ptr [[TMP12]], align 2
; CHECK-NEXT: [[TMP13:%.*]] = getelementptr inbounds nuw <{ i32, i32, [6 x i8], i16, i32, i32, [4 x i8], float }>, ptr [[TMP0]], i32 0, i32 7
; CHECK-NEXT: store float [[B]], ptr [[TMP13]], align 4
-; CHECK-NEXT: call void @__instrumentor_post_function(ptr @foo, ptr @__instrumentor_.str.2, i32 2, ptr [[TMP0]], i8 0, i32 -6) #[[ATTR1]]
+; CHECK-NEXT: call void @__instrumentor_post_function(ptr @foo, ptr @__instrumentor_.str.3, i32 2, ptr [[TMP0]], i8 0, i32 -7) #[[ATTR1]]
; CHECK-NEXT: ret float [[TMP6]]
;
entry:
diff --git a/llvm/test/Instrumentation/Instrumentor/call-config.json b/llvm/test/Instrumentation/Instrumentor/call-config.json
new file mode 100644
index 0000000000000..7316f2a5141f5
--- /dev/null
+++ b/llvm/test/Instrumentation/Instrumentor/call-config.json
@@ -0,0 +1,29 @@
+{
+ "instruction_pre": {
+ "call": {
+ "enabled": true,
+ "callee": true,
+ "callee_name": true,
+ "num_arguments": true,
+ "arguments": true,
+ "return_value_size": true,
+ "return_type_id": true,
+ "return_sub_type_id": true,
+ "id": true
+ }
+ },
+ "instruction_post": {
+ "call": {
+ "enabled": true,
+ "callee": true,
+ "callee_name": true,
+ "num_arguments": true,
+ "arguments": true,
+ "return_value": true,
+ "return_value_size": true,
+ "return_type_id": true,
+ "return_sub_type_id": true,
+ "id": true
+ }
+ }
+}
diff --git a/llvm/test/Instrumentation/Instrumentor/call-name-filter-config.json b/llvm/test/Instrumentation/Instrumentor/call-name-filter-config.json
new file mode 100644
index 0000000000000..58a09e7a68713
--- /dev/null
+++ b/llvm/test/Instrumentation/Instrumentor/call-name-filter-config.json
@@ -0,0 +1,20 @@
+{
+ "instruction_pre": {
+ "call": {
+ "enabled": true,
+ "filter": "callee_name==\"foo\"",
+ "callee": true,
+ "callee_name": true,
+ "id": true
+ }
+ },
+ "instruction_post": {
+ "call": {
+ "enabled": true,
+ "filter": "callee_name==\"foo\"",
+ "callee": true,
+ "callee_name": true,
+ "id": true
+ }
+ }
+}
diff --git a/llvm/test/Instrumentation/Instrumentor/call-name-filter.ll b/llvm/test/Instrumentation/Instrumentor/call-name-filter.ll
new file mode 100644
index 0000000000000..1ed9a0244f04b
--- /dev/null
+++ b/llvm/test/Instrumentation/Instrumentor/call-name-filter.ll
@@ -0,0 +1,29 @@
+; RUN: opt -passes=instrumentor -instrumentor-read-config-files=%S/call-name-filter-config.json -S < %s | FileCheck %s
+
+declare i32 @foo(i32)
+declare i32 @bar(i32)
+
+define i32 @caller(ptr %fp, i32 %x) {
+; CHECK-LABEL: define i32 @caller(
+; CHECK: call void @__instrumentor_pre_call(ptr @foo, ptr @{{.*}}, i32 1)
+; CHECK-NEXT: %foo = call i32 @foo(i32 %x)
+; CHECK-NEXT: call void @__instrumentor_post_call(ptr @foo, ptr @{{.*}}, i32 -1)
+; CHECK-NEXT: %bar = call i32 @bar(i32 %x)
+; CHECK-NEXT: %ind = call i32 %fp(i32 %x)
+; CHECK-NEXT: %sum = add i32 %foo, %bar
+; CHECK-NEXT: %ret = add i32 %sum, %ind
+; CHECK-NEXT: ret i32 %ret
+ %foo = call i32 @foo(i32 %x)
+ %bar = call i32 @bar(i32 %x)
+ %ind = call i32 %fp(i32 %x)
+ %sum = add i32 %foo, %bar
+ %ret = add i32 %sum, %ind
+ ret i32 %ret
+}
+
+; CHECK: declare void @__instrumentor_pre_call(ptr, ptr, i32)
+; CHECK: declare void @__instrumentor_post_call(ptr, ptr, i32)
+; CHECK-NOT: __instrumentor_pre_call(ptr @bar
+; CHECK-NOT: __instrumentor_post_call(ptr @bar
+; CHECK-NOT: __instrumentor_pre_call(ptr %fp
+; CHECK-NOT: __instrumentor_post_call(ptr %fp
diff --git a/llvm/test/Instrumentation/Instrumentor/call.ll b/llvm/test/Instrumentation/Instrumentor/call.ll
new file mode 100644
index 0000000000000..687311252a36d
--- /dev/null
+++ b/llvm/test/Instrumentation/Instrumentor/call.ll
@@ -0,0 +1,26 @@
+; RUN: opt -passes=instrumentor -instrumentor-read-config-files=%S/call-config.json -S < %s | FileCheck %s
+
+declare i32 @foo(i32, ptr)
+declare void @bar()
+
+define i32 @caller(ptr %p, ptr %fp, i32 %x) {
+; CHECK-LABEL: define i32 @caller(
+; CHECK: call void @__instrumentor_pre_call(ptr @foo, ptr @{{.*}}, i32 2, ptr %{{.*}}, i64 4, i32 {{[0-9]+}}, i32 -1, i32 1)
+; CHECK: %res = call i32 @foo(i32 %x, ptr %p)
+; CHECK: call void @__instrumentor_post_call(ptr @foo, ptr @{{.*}}, i32 2, ptr %{{.*}}, i64 %{{.*}}, i64 4, i32 {{[0-9]+}}, i32 -1, i32 -1)
+; CHECK: call void @__instrumentor_pre_call(ptr %fp, ptr @{{.*}}, i32 1, ptr %{{.*}}, i64 4, i32 {{[0-9]+}}, i32 -1, i32 2)
+; CHECK: %ind = call i32 %fp(i32 %x)
+...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/206658
More information about the llvm-commits
mailing list