[llvm-branch-commits] [clang] [llvm] Feature/dynamic def use (PR #212189)
Glisanov Andrej via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Mon Jul 27 00:49:03 PDT 2026
https://github.com/CiberMonah created https://github.com/llvm/llvm-project/pull/212189
None
>From f5fe592e126f08e478c9da3ddf0c60c3009c28f6 Mon Sep 17 00:00:00 2001
From: ag <glisanov.andrej at yandex.ru>
Date: Fri, 24 Jul 2026 01:29:10 +0300
Subject: [PATCH 01/21] Added no op pass
---
.../Instrumentation/DefUseInstrumentation.h | 19 +++++++++++++++++++
llvm/lib/Passes/PassBuilder.cpp | 1 +
llvm/lib/Passes/PassRegistry.def | 1 +
llvm/test/Instrumentation/DefUse/basic.ll | 6 ++++++
4 files changed, 27 insertions(+)
create mode 100644 llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
create mode 100644 llvm/test/Instrumentation/DefUse/basic.ll
diff --git a/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h b/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
new file mode 100644
index 0000000000000..972827fd6bfb6
--- /dev/null
+++ b/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
@@ -0,0 +1,19 @@
+#ifndef LLVM_TRANSFORMS_INSTRUMENTATION_DEFUSEINSTRUMENTATION_H
+#define LLVM_TRANSFORMS_INSTRUMENTATION_DEFUSEINSTRUMENTATION_H
+
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+
+class Module;
+
+struct DefUseInstrumentationPass
+ : PassInfoMixin<DefUseInstrumentationPass> {
+ PreservedAnalyses run(Module &, ModuleAnalysisManager &) {
+ return PreservedAnalyses::all();
+ }
+};
+
+} // namespace llvm
+
+#endif // LLVM_TRANSFORMS_INSTRUMENTATION_DEFUSEINSTRUMENTATION_H
\ No newline at end of file
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index 5dbb1e2f49871..0d84798337cbf 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -185,6 +185,7 @@
#include "llvm/Transforms/Instrumentation/CGProfile.h"
#include "llvm/Transforms/Instrumentation/ControlHeightReduction.h"
#include "llvm/Transforms/Instrumentation/DataFlowSanitizer.h"
+#include "llvm/Transforms/Instrumentation/DefUseInstrumentation.h"
#include "llvm/Transforms/Instrumentation/GCOVProfiler.h"
#include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h"
#include "llvm/Transforms/Instrumentation/InstrOrderFile.h"
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index 3b92823cd283b..c100505dfad24 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -94,6 +94,7 @@ MODULE_PASS("metarenamer", MetaRenamerPass())
MODULE_PASS("module-inline", ModuleInlinerPass())
MODULE_PASS("name-anon-globals", NameAnonGlobalPass())
MODULE_PASS("no-op-module", NoOpModulePass())
+MODULE_PASS("def-use-instrumentation", DefUseInstrumentationPass())
MODULE_PASS("nsan", NumericalStabilitySanitizerPass())
MODULE_PASS("objc-arc-apelim", ObjCARCAPElimPass())
MODULE_PASS("openmp-opt", OpenMPOptPass())
diff --git a/llvm/test/Instrumentation/DefUse/basic.ll b/llvm/test/Instrumentation/DefUse/basic.ll
new file mode 100644
index 0000000000000..380bc4594edc5
--- /dev/null
+++ b/llvm/test/Instrumentation/DefUse/basic.ll
@@ -0,0 +1,6 @@
+; RUN: opt -passes=def-use-instrumentation -disable-output %s
+
+define i32 @main() {
+entry:
+ ret i32 0
+}
\ No newline at end of file
>From 6a17afa36c24f9b88d9ae6248979c9dc1db3203a Mon Sep 17 00:00:00 2001
From: ag <glisanov.andrej at yandex.ru>
Date: Sat, 25 Jul 2026 21:53:16 +0300
Subject: [PATCH 02/21] Find main function in def-use pass
---
.../Transforms/Instrumentation/DefUseInstrumentation.h | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h b/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
index 972827fd6bfb6..66c9f71da8e7c 100644
--- a/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
+++ b/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
@@ -2,6 +2,8 @@
#define LLVM_TRANSFORMS_INSTRUMENTATION_DEFUSEINSTRUMENTATION_H
#include "llvm/IR/PassManager.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/Module.h"
namespace llvm {
@@ -9,7 +11,11 @@ class Module;
struct DefUseInstrumentationPass
: PassInfoMixin<DefUseInstrumentationPass> {
- PreservedAnalyses run(Module &, ModuleAnalysisManager &) {
+ PreservedAnalyses run(Module &M, ModuleAnalysisManager &) {
+ Function* Main = M.getFunction("main");
+ if (!Main || Main->isDeclaration()) {
+ return PreservedAnalyses::all();
+ }
return PreservedAnalyses::all();
}
};
>From eca4336c1545ad00344bbcc12aa5f0619f7d2687 Mon Sep 17 00:00:00 2001
From: ag <glisanov.andrej at yandex.ru>
Date: Sat, 25 Jul 2026 23:47:58 +0300
Subject: [PATCH 03/21] added callback func
---
.../Instrumentation/DefUseInstrumentation.h | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h b/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
index 66c9f71da8e7c..700b6fe2cda93 100644
--- a/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
+++ b/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
@@ -1,9 +1,13 @@
#ifndef LLVM_TRANSFORMS_INSTRUMENTATION_DEFUSEINSTRUMENTATION_H
#define LLVM_TRANSFORMS_INSTRUMENTATION_DEFUSEINSTRUMENTATION_H
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
+#include "llvm/IR/Type.h"
namespace llvm {
@@ -16,7 +20,13 @@ struct DefUseInstrumentationPass
if (!Main || Main->isDeclaration()) {
return PreservedAnalyses::all();
}
- return PreservedAnalyses::all();
+ LLVMContext& Ctx = M.getContext();
+
+ FunctionType* HookType = FunctionType::get(Type::getVoidTy(Ctx), false);
+
+ FunctionCallee funccall = M.getOrInsertFunction("__def_use_trace_main_enter", HookType);
+
+ return PreservedAnalyses::none();
}
};
>From 9ec305f707d5f26b37f1abfe2d3670bbde2bba7b Mon Sep 17 00:00:00 2001
From: ag <glisanov.andrej at yandex.ru>
Date: Sun, 26 Jul 2026 00:50:04 +0300
Subject: [PATCH 04/21] added test def use
---
llvm/test/Instrumentation/DefUse/basic.ll | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/llvm/test/Instrumentation/DefUse/basic.ll b/llvm/test/Instrumentation/DefUse/basic.ll
index 380bc4594edc5..12d179b0c2370 100644
--- a/llvm/test/Instrumentation/DefUse/basic.ll
+++ b/llvm/test/Instrumentation/DefUse/basic.ll
@@ -1,6 +1,8 @@
-; RUN: opt -passes=def-use-instrumentation -disable-output %s
+; RUN: opt -passes=def-use-instrumentation -S %s | FileCheck %s
define i32 @main() {
entry:
ret i32 0
-}
\ No newline at end of file
+}
+
+; CHECK: declare void @__def_use_trace_main_enter()
\ No newline at end of file
>From f53663e91e4e7507d557962cd31e914d4f595999 Mon Sep 17 00:00:00 2001
From: ag <glisanov.andrej at yandex.ru>
Date: Sun, 26 Jul 2026 01:49:54 +0300
Subject: [PATCH 05/21] added multifunctional detection enter
---
.../Instrumentation/DefUseInstrumentation.h | 23 +++++++++++--------
llvm/test/Instrumentation/DefUse/basic.ll | 13 ++++++++++-
2 files changed, 26 insertions(+), 10 deletions(-)
diff --git a/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h b/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
index 700b6fe2cda93..8bdcbc0dfb9ad 100644
--- a/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
+++ b/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
@@ -1,6 +1,7 @@
#ifndef LLVM_TRANSFORMS_INSTRUMENTATION_DEFUSEINSTRUMENTATION_H
#define LLVM_TRANSFORMS_INSTRUMENTATION_DEFUSEINSTRUMENTATION_H
+#include "llvm/ADT/StringRef.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/LLVMContext.h"
@@ -16,16 +17,20 @@ class Module;
struct DefUseInstrumentationPass
: PassInfoMixin<DefUseInstrumentationPass> {
PreservedAnalyses run(Module &M, ModuleAnalysisManager &) {
- Function* Main = M.getFunction("main");
- if (!Main || Main->isDeclaration()) {
- return PreservedAnalyses::all();
- }
- LLVMContext& Ctx = M.getContext();
-
- FunctionType* HookType = FunctionType::get(Type::getVoidTy(Ctx), false);
-
- FunctionCallee funccall = M.getOrInsertFunction("__def_use_trace_main_enter", HookType);
+ LLVMContext& Ctx = M.getContext();
+ IRBuilder<> Builder(Ctx);
+
+ for (Function &F : M) {
+ if (F.isDeclaration()) {
+ return PreservedAnalyses::all();
+ }
+ Builder.SetInsertPointPastAllocas(&F);
+ FunctionType* HookType = FunctionType::get(Type::getVoidTy(Ctx), false);
+ FunctionCallee Hook = M.getOrInsertFunction("__def_use_trace_enter", HookType);
+ Builder.CreateCall(Hook);
+ }
+
return PreservedAnalyses::none();
}
};
diff --git a/llvm/test/Instrumentation/DefUse/basic.ll b/llvm/test/Instrumentation/DefUse/basic.ll
index 12d179b0c2370..1d1cbc6a41ded 100644
--- a/llvm/test/Instrumentation/DefUse/basic.ll
+++ b/llvm/test/Instrumentation/DefUse/basic.ll
@@ -2,7 +2,18 @@
define i32 @main() {
entry:
+ %x = alloca i32
ret i32 0
}
-; CHECK: declare void @__def_use_trace_main_enter()
\ No newline at end of file
+define i32 @foo() {
+entry:
+ %x = alloca i32
+ ret i32 0
+}
+
+define i32 @bar() {
+entry:
+ %x = alloca i32
+ ret i32 0
+}
>From cbb1463b52815732e33840d6f48b7db9dc20313d Mon Sep 17 00:00:00 2001
From: ag <glisanov.andrej at yandex.ru>
Date: Sun, 26 Jul 2026 02:03:14 +0300
Subject: [PATCH 06/21] bug fix + test with no body func
---
.../Instrumentation/DefUseInstrumentation.h | 6 +++---
llvm/test/Instrumentation/DefUse/basic.ll | 17 +++++++++++++++++
2 files changed, 20 insertions(+), 3 deletions(-)
diff --git a/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h b/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
index 8bdcbc0dfb9ad..40065d29dc54b 100644
--- a/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
+++ b/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
@@ -20,14 +20,14 @@ struct DefUseInstrumentationPass
LLVMContext& Ctx = M.getContext();
IRBuilder<> Builder(Ctx);
+ FunctionType* HookType = FunctionType::get(Type::getVoidTy(Ctx), false);
+ FunctionCallee Hook = M.getOrInsertFunction("__def_use_trace_enter", HookType);
for (Function &F : M) {
if (F.isDeclaration()) {
- return PreservedAnalyses::all();
+ continue;
}
Builder.SetInsertPointPastAllocas(&F);
- FunctionType* HookType = FunctionType::get(Type::getVoidTy(Ctx), false);
- FunctionCallee Hook = M.getOrInsertFunction("__def_use_trace_enter", HookType);
Builder.CreateCall(Hook);
}
diff --git a/llvm/test/Instrumentation/DefUse/basic.ll b/llvm/test/Instrumentation/DefUse/basic.ll
index 1d1cbc6a41ded..9d5bfe6b681eb 100644
--- a/llvm/test/Instrumentation/DefUse/basic.ll
+++ b/llvm/test/Instrumentation/DefUse/basic.ll
@@ -1,5 +1,7 @@
; RUN: opt -passes=def-use-instrumentation -S %s | FileCheck %s
+declare void @nobodyfunc ()
+
define i32 @main() {
entry:
%x = alloca i32
@@ -17,3 +19,18 @@ entry:
%x = alloca i32
ret i32 0
}
+
+; CHECK: declare void @nobodyfunc()
+; CHECK-LABEL: define i32 @main()
+; CHECK: %x = alloca i32
+; CHECK-NEXT: call void @__def_use_trace_enter()
+; CHECK-NEXT: ret i32 0
+; CHECK-LABEL: define i32 @foo()
+; CHECK: %x = alloca i32
+; CHECK-NEXT: call void @__def_use_trace_enter()
+; CHECK-NEXT: ret i32 0
+; CHECK-LABEL: define i32 @bar()
+; CHECK: %x = alloca i32
+; CHECK-NEXT: call void @__def_use_trace_enter()
+; CHECK-NEXT: ret i32 0
+; CHECK: declare void @__def_use_trace_enter()
>From 6f548f15f77c748f080389bc6c7e71e6f14d0b60 Mon Sep 17 00:00:00 2001
From: ag <glisanov.andrej at yandex.ru>
Date: Sun, 26 Jul 2026 02:28:58 +0300
Subject: [PATCH 07/21] added indexation of callbacks
---
.../Instrumentation/DefUseInstrumentation.h | 13 ++++++++++---
llvm/test/Instrumentation/DefUse/basic.ll | 17 +----------------
2 files changed, 11 insertions(+), 19 deletions(-)
diff --git a/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h b/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
index 40065d29dc54b..4d8c97c13a9a0 100644
--- a/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
+++ b/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
@@ -2,6 +2,8 @@
#define LLVM_TRANSFORMS_INSTRUMENTATION_DEFUSEINSTRUMENTATION_H
#include "llvm/ADT/StringRef.h"
+#include "llvm/IR/Constant.h"
+#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/LLVMContext.h"
@@ -9,6 +11,7 @@
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
+#include <cstdint>
namespace llvm {
@@ -20,15 +23,19 @@ struct DefUseInstrumentationPass
LLVMContext& Ctx = M.getContext();
IRBuilder<> Builder(Ctx);
- FunctionType* HookType = FunctionType::get(Type::getVoidTy(Ctx), false);
+
+ FunctionType* HookType = FunctionType::get(Type::getVoidTy(Ctx), {Type::getInt64Ty(Ctx)}, false);
FunctionCallee Hook = M.getOrInsertFunction("__def_use_trace_enter", HookType);
+ uint64_t CallID = 0;
+
for (Function &F : M) {
if (F.isDeclaration()) {
continue;
}
- Builder.SetInsertPointPastAllocas(&F);
- Builder.CreateCall(Hook);
+ Builder.SetInsertPointPastAllocas(&F );
+ Builder.CreateCall(Hook, Builder.getInt64(CallID));
+ CallID++;
}
return PreservedAnalyses::none();
diff --git a/llvm/test/Instrumentation/DefUse/basic.ll b/llvm/test/Instrumentation/DefUse/basic.ll
index 9d5bfe6b681eb..ac98f75520104 100644
--- a/llvm/test/Instrumentation/DefUse/basic.ll
+++ b/llvm/test/Instrumentation/DefUse/basic.ll
@@ -18,19 +18,4 @@ define i32 @bar() {
entry:
%x = alloca i32
ret i32 0
-}
-
-; CHECK: declare void @nobodyfunc()
-; CHECK-LABEL: define i32 @main()
-; CHECK: %x = alloca i32
-; CHECK-NEXT: call void @__def_use_trace_enter()
-; CHECK-NEXT: ret i32 0
-; CHECK-LABEL: define i32 @foo()
-; CHECK: %x = alloca i32
-; CHECK-NEXT: call void @__def_use_trace_enter()
-; CHECK-NEXT: ret i32 0
-; CHECK-LABEL: define i32 @bar()
-; CHECK: %x = alloca i32
-; CHECK-NEXT: call void @__def_use_trace_enter()
-; CHECK-NEXT: ret i32 0
-; CHECK: declare void @__def_use_trace_enter()
+}
\ No newline at end of file
>From 70cbfca1f30cbf34afe7399079829e2f821b9f6f Mon Sep 17 00:00:00 2001
From: ag <glisanov.andrej at yandex.ru>
Date: Sun, 26 Jul 2026 02:44:55 +0300
Subject: [PATCH 08/21] added static ID to intstrumentations
---
.../Instrumentation/DefUseInstrumentation.h | 12 +++++++++---
llvm/test/Instrumentation/DefUse/basic.ll | 19 ++++---------------
2 files changed, 13 insertions(+), 18 deletions(-)
diff --git a/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h b/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
index 4d8c97c13a9a0..928b0e28b6c26 100644
--- a/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
+++ b/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
@@ -2,10 +2,12 @@
#define LLVM_TRANSFORMS_INSTRUMENTATION_DEFUSEINSTRUMENTATION_H
#include "llvm/ADT/StringRef.h"
+#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
+#include "llvm/IR/Instruction.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/IRBuilder.h"
@@ -33,9 +35,13 @@ struct DefUseInstrumentationPass
if (F.isDeclaration()) {
continue;
}
- Builder.SetInsertPointPastAllocas(&F );
- Builder.CreateCall(Hook, Builder.getInt64(CallID));
- CallID++;
+ for (BasicBlock &BB : F) {
+ for (Instruction &I : BB) {
+ Builder.SetInsertPoint(&I);
+ Builder.CreateCall(Hook, Builder.getInt64(CallID));
+ CallID++;
+ }
+ }
}
return PreservedAnalyses::none();
diff --git a/llvm/test/Instrumentation/DefUse/basic.ll b/llvm/test/Instrumentation/DefUse/basic.ll
index ac98f75520104..5583fe4e0763d 100644
--- a/llvm/test/Instrumentation/DefUse/basic.ll
+++ b/llvm/test/Instrumentation/DefUse/basic.ll
@@ -2,20 +2,9 @@
declare void @nobodyfunc ()
-define i32 @main() {
+define i32 @foo(i32 %x) {
entry:
- %x = alloca i32
- ret i32 0
-}
-
-define i32 @foo() {
-entry:
- %x = alloca i32
- ret i32 0
-}
-
-define i32 @bar() {
-entry:
- %x = alloca i32
- ret i32 0
+ %a = add i32 %x, 1
+ %b = mul i32 %a, 2
+ ret i32 %b
}
\ No newline at end of file
>From c78d470f343b34dfe5dbcf2a9dd84da4334d2aa3 Mon Sep 17 00:00:00 2001
From: ag <glisanov.andrej at yandex.ru>
Date: Sun, 26 Jul 2026 17:39:34 +0300
Subject: [PATCH 09/21] Collect static SSA def use dependences
---
.../Instrumentation/DefUseInstrumentation.h | 49 +++++++++++++++++--
1 file changed, 44 insertions(+), 5 deletions(-)
diff --git a/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h b/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
index 928b0e28b6c26..f6f0588d40603 100644
--- a/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
+++ b/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
@@ -6,6 +6,7 @@
#include "llvm/IR/Constant.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/LLVMContext.h"
@@ -13,6 +14,9 @@
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
+#include "llvm/IR/Use.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Transforms/IPO/SampleProfileProbe.h"
#include <cstdint>
namespace llvm {
@@ -25,10 +29,14 @@ struct DefUseInstrumentationPass
LLVMContext& Ctx = M.getContext();
IRBuilder<> Builder(Ctx);
+ DenseMap<Instruction*, uint64_t> InstIDs; // Мапа, для того чтоб повторный вызов инструкции вспоминался и айдишник ёё брался
+ SmallVector<Instruction *> Instructions; // Чтоб модуль заново не обходить, а по вектору пробежаться
FunctionType* HookType = FunctionType::get(Type::getVoidTy(Ctx), {Type::getInt64Ty(Ctx)}, false);
FunctionCallee Hook = M.getOrInsertFunction("__def_use_trace_enter", HookType);
+
+ // первый обход заполняет мапу инструкция - ID
uint64_t CallID = 0;
for (Function &F : M) {
@@ -37,16 +45,47 @@ struct DefUseInstrumentationPass
}
for (BasicBlock &BB : F) {
for (Instruction &I : BB) {
- Builder.SetInsertPoint(&I);
- Builder.CreateCall(Hook, Builder.getInt64(CallID));
+ Instructions.push_back(&I);
+ InstIDs[&I] = CallID;
CallID++;
}
}
}
-
+ // второй обход создает зависимости, на основе мапы, использует ли функция результат уже другой функции
+
+ for (Instruction *I : Instructions) {
+ uint64_t UseID = InstIDs.lookup(I);
+
+ for (Use &Operand : I->operands()) {
+ Value *V = Operand.get();
+
+ Instruction *Def = dyn_cast<Instruction>(V);
+
+ if (!Def) {
+ continue;
+ }
+
+ if (!InstIDs.contains(Def))
+ continue;
+
+ uint64_t DefID = InstIDs.lookup(Def);
+
+ errs() << "DEF " << DefID <<
+ "-> USE " << UseID << "\n";
+ }
+ }
+
+ // третий обход чтоб вставить колбеки
+ for (Instruction *I : Instructions) {
+ uint64_t ID = InstIDs.lookup(I);
+
+ Builder.SetInsertPoint(I);
+ Builder.CreateCall(Hook, Builder.getInt64(ID));
+ }
+
return PreservedAnalyses::none();
- }
-};
+ }
+ };
} // namespace llvm
>From f7e9a370511f9fd0b81e92710984a5eafcef83f1 Mon Sep 17 00:00:00 2001
From: ag <glisanov.andrej at yandex.ru>
Date: Sun, 26 Jul 2026 17:58:36 +0300
Subject: [PATCH 10/21] Added dynamic ssa dependences
---
.../Instrumentation/DefUseInstrumentation.h | 19 ++++++++-----------
llvm/test/Instrumentation/DefUse/basic.ll | 15 ++++++++++++++-
2 files changed, 22 insertions(+), 12 deletions(-)
diff --git a/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h b/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
index f6f0588d40603..e6f6023f72542 100644
--- a/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
+++ b/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
@@ -33,7 +33,8 @@ struct DefUseInstrumentationPass
SmallVector<Instruction *> Instructions; // Чтоб модуль заново не обходить, а по вектору пробежаться
FunctionType* HookType = FunctionType::get(Type::getVoidTy(Ctx), {Type::getInt64Ty(Ctx)}, false);
- FunctionCallee Hook = M.getOrInsertFunction("__def_use_trace_enter", HookType);
+ FunctionCallee Hook_inst = M.getOrInsertFunction("__def_use_trace_inst", HookType);
+ FunctionCallee Hook_use = M.getOrInsertFunction("__def_use_trace_ssa_use", HookType);
// первый обход заполняет мапу инструкция - ID
@@ -51,10 +52,12 @@ struct DefUseInstrumentationPass
}
}
}
- // второй обход создает зависимости, на основе мапы, использует ли функция результат уже другой функции
+ // второй обход создает зависимости, на основе мапы, использует ли функция результат уже другой инструкции
for (Instruction *I : Instructions) {
uint64_t UseID = InstIDs.lookup(I);
+ Builder.SetInsertPoint(I);
+ Builder.CreateCall(Hook_inst, Builder.getInt64(UseID));
for (Use &Operand : I->operands()) {
Value *V = Operand.get();
@@ -69,20 +72,14 @@ struct DefUseInstrumentationPass
continue;
uint64_t DefID = InstIDs.lookup(Def);
-
+
+ Builder.CreateCall(Hook_use, Builder.getInt64(DefID));
+
errs() << "DEF " << DefID <<
"-> USE " << UseID << "\n";
}
}
- // третий обход чтоб вставить колбеки
- for (Instruction *I : Instructions) {
- uint64_t ID = InstIDs.lookup(I);
-
- Builder.SetInsertPoint(I);
- Builder.CreateCall(Hook, Builder.getInt64(ID));
- }
-
return PreservedAnalyses::none();
}
};
diff --git a/llvm/test/Instrumentation/DefUse/basic.ll b/llvm/test/Instrumentation/DefUse/basic.ll
index 5583fe4e0763d..ad2ff13d37dda 100644
--- a/llvm/test/Instrumentation/DefUse/basic.ll
+++ b/llvm/test/Instrumentation/DefUse/basic.ll
@@ -7,4 +7,17 @@ entry:
%a = add i32 %x, 1
%b = mul i32 %a, 2
ret i32 %b
-}
\ No newline at end of file
+}
+
+; CHECK-LABEL: define i32 @foo(i32 %x)
+; CHECK: call void @__def_use_trace_inst(i64 0)
+; CHECK-NEXT: %a = add i32 %x, 1
+; CHECK-NEXT: call void @__def_use_trace_inst(i64 1)
+; CHECK-NEXT: call void @__def_use_trace_ssa_use(i64 0)
+; CHECK-NEXT: %b = mul i32 %a, 2
+; CHECK-NEXT: call void @__def_use_trace_inst(i64 2)
+; CHECK-NEXT: call void @__def_use_trace_ssa_use(i64 1)
+; CHECK-NEXT: ret i32 %b
+
+; CHECK: declare void @__def_use_trace_inst(i64)
+; CHECK: declare void @__def_use_trace_ssa_use(i64)
\ No newline at end of file
>From c76386136735442172443a1b73026b93541b2da8 Mon Sep 17 00:00:00 2001
From: ag <glisanov.andrej at yandex.ru>
Date: Sun, 26 Jul 2026 18:27:57 +0300
Subject: [PATCH 11/21] Recognize load and store instructions
---
.../Instrumentation/DefUseInstrumentation.h | 24 +++++++++++++++++++
llvm/test/Instrumentation/DefUse/basic.ll | 23 ++++--------------
2 files changed, 28 insertions(+), 19 deletions(-)
diff --git a/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h b/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
index e6f6023f72542..6eb0c1b3995b8 100644
--- a/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
+++ b/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
@@ -17,6 +17,12 @@
#include "llvm/IR/Use.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Transforms/IPO/SampleProfileProbe.h"
+
+
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Instructions.h"
+
+
#include <cstdint>
namespace llvm {
@@ -36,6 +42,11 @@ struct DefUseInstrumentationPass
FunctionCallee Hook_inst = M.getOrInsertFunction("__def_use_trace_inst", HookType);
FunctionCallee Hook_use = M.getOrInsertFunction("__def_use_trace_ssa_use", HookType);
+ FunctionType *MemoryHookType = FunctionType::get(Type::getVoidTy(Ctx),{Type::getInt64Ty(Ctx), Type::getInt64Ty(Ctx)},false);
+ FunctionCallee HookLoad = M.getOrInsertFunction("__def_use_trace_load", MemoryHookType);
+ FunctionCallee HookStore = M.getOrInsertFunction("__def_use_trace_store", MemoryHookType);
+
+ const DataLayout &DL = M.getDataLayout(); // DataLayout::getTypeStoreSize() чтоб получить размер значения в памяти
// первый обход заполняет мапу инструкция - ID
uint64_t CallID = 0;
@@ -59,6 +70,19 @@ struct DefUseInstrumentationPass
Builder.SetInsertPoint(I);
Builder.CreateCall(Hook_inst, Builder.getInt64(UseID));
+ if (auto *LI = dyn_cast<LoadInst>(I)) {
+ Value *PointerOperand = LI->getPointerOperand();
+
+ errs() << "Found LOAD: " << *LI << '\n';
+ errs() << "Load pointer operand: " << *PointerOperand << '\n';
+
+ } else if (auto *SI = dyn_cast<StoreInst>(I)) {
+ Value *PointerOperand = SI->getPointerOperand();
+
+ errs() << "Found STORE: " << *SI << '\n';
+ errs() << "Store pointer operand: " << *PointerOperand << '\n';
+ }
+
for (Use &Operand : I->operands()) {
Value *V = Operand.get();
diff --git a/llvm/test/Instrumentation/DefUse/basic.ll b/llvm/test/Instrumentation/DefUse/basic.ll
index ad2ff13d37dda..2aad422fde013 100644
--- a/llvm/test/Instrumentation/DefUse/basic.ll
+++ b/llvm/test/Instrumentation/DefUse/basic.ll
@@ -1,23 +1,8 @@
; RUN: opt -passes=def-use-instrumentation -S %s | FileCheck %s
-declare void @nobodyfunc ()
-
-define i32 @foo(i32 %x) {
+define i32 @memory_test(ptr %p, i32 %x) {
entry:
- %a = add i32 %x, 1
- %b = mul i32 %a, 2
- ret i32 %b
+ store i32 %x, ptr %p
+ %value = load i32, ptr %p
+ ret i32 %value
}
-
-; CHECK-LABEL: define i32 @foo(i32 %x)
-; CHECK: call void @__def_use_trace_inst(i64 0)
-; CHECK-NEXT: %a = add i32 %x, 1
-; CHECK-NEXT: call void @__def_use_trace_inst(i64 1)
-; CHECK-NEXT: call void @__def_use_trace_ssa_use(i64 0)
-; CHECK-NEXT: %b = mul i32 %a, 2
-; CHECK-NEXT: call void @__def_use_trace_inst(i64 2)
-; CHECK-NEXT: call void @__def_use_trace_ssa_use(i64 1)
-; CHECK-NEXT: ret i32 %b
-
-; CHECK: declare void @__def_use_trace_inst(i64)
-; CHECK: declare void @__def_use_trace_ssa_use(i64)
\ No newline at end of file
>From b9376520e32be76ceb7c1f2bd2a9996dceb38c1c Mon Sep 17 00:00:00 2001
From: ag <glisanov.andrej at yandex.ru>
Date: Sun, 26 Jul 2026 19:12:11 +0300
Subject: [PATCH 12/21] Instrument load and store memory accesses
---
.../Instrumentation/DefUseInstrumentation.h | 31 ++++++++++++++++---
1 file changed, 27 insertions(+), 4 deletions(-)
diff --git a/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h b/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
index 6eb0c1b3995b8..dc1ff9dff5f5e 100644
--- a/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
+++ b/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
@@ -70,17 +70,40 @@ struct DefUseInstrumentationPass
Builder.SetInsertPoint(I);
Builder.CreateCall(Hook_inst, Builder.getInt64(UseID));
+ // Load и Store отельно обрабатываем
if (auto *LI = dyn_cast<LoadInst>(I)) {
Value *PointerOperand = LI->getPointerOperand();
- errs() << "Found LOAD: " << *LI << '\n';
- errs() << "Load pointer operand: " << *PointerOperand << '\n';
+ Value *Address =
+ Builder.CreatePtrToInt(PointerOperand, Type::getInt64Ty(Ctx));
+
+ errs() << "LOAD address value: " << *Address << '\n';
+
+ TypeSize LoadSize = DL.getTypeStoreSize(LI->getType());
+
+ errs() << "Load size: " << LoadSize.getFixedValue() << '\n';
+
+ uint64_t Size = LoadSize.getFixedValue();
+
+ Builder.CreateCall(HookLoad, {Address, Builder.getInt64(Size)});
} else if (auto *SI = dyn_cast<StoreInst>(I)) {
Value *PointerOperand = SI->getPointerOperand();
- errs() << "Found STORE: " << *SI << '\n';
- errs() << "Store pointer operand: " << *PointerOperand << '\n';
+ Value *Address =
+ Builder.CreatePtrToInt(PointerOperand, Type::getInt64Ty(Ctx));
+
+ errs() << "Store address value: " << *Address << '\n';
+
+ Type *StoredType = SI->getValueOperand()->getType();
+ TypeSize StoreSize = DL.getTypeStoreSize(StoredType);
+
+ errs() << "Store size: " << StoreSize.getFixedValue() << '\n';
+
+
+ uint64_t Size = StoreSize.getFixedValue();
+
+ Builder.CreateCall(HookStore, {Address, Builder.getInt64(Size)});
}
for (Use &Operand : I->operands()) {
>From b5c3998b1a0744848fd261dcef940a4b7f6803dc Mon Sep 17 00:00:00 2001
From: ag <glisanov.andrej at yandex.ru>
Date: Sun, 26 Jul 2026 19:12:45 +0300
Subject: [PATCH 13/21] Add initial dynamic def-use runtime
---
llvm/tools/def-use-runtime/DefUseRuntime.cpp | 50 ++++++++++++++++++++
1 file changed, 50 insertions(+)
create mode 100644 llvm/tools/def-use-runtime/DefUseRuntime.cpp
diff --git a/llvm/tools/def-use-runtime/DefUseRuntime.cpp b/llvm/tools/def-use-runtime/DefUseRuntime.cpp
new file mode 100644
index 0000000000000..b1948a81a6633
--- /dev/null
+++ b/llvm/tools/def-use-runtime/DefUseRuntime.cpp
@@ -0,0 +1,50 @@
+#include <cstdint>
+#include <cstdio>
+#include <unordered_map>
+#include <iostream>
+#include <iomanip>
+
+static std::uint64_t NextEventID = 0;
+static std::uint64_t CurrentEventID = 0;
+
+static std::unordered_map<std::uint64_t, std::uint64_t> LastEvent;
+
+extern "C" void __def_use_trace_inst(std::uint64_t InstID) {
+ CurrentEventID = NextEventID++;
+
+ std::fprintf(
+ stderr,
+ "EVENT %llu INST %llu\n",
+ static_cast<unsigned long long>(CurrentEventID),
+ static_cast<unsigned long long>(InstID));
+
+ LastEvent[InstID] = CurrentEventID;
+}
+
+extern "C" void __def_use_trace_ssa_use(std::uint64_t DefID) {
+ auto It = LastEvent.find(DefID);
+
+ if (It == LastEvent.end()) {
+ std::fprintf(
+ stderr,
+ "MISSING DEF INST %llu\n",
+ static_cast<unsigned long long>(DefID));
+ return;
+ }
+
+ std::fprintf(
+ stderr,
+ "EDGE %llu -> %llu\n",
+ static_cast<unsigned long long>(It->second),
+ static_cast<unsigned long long>(CurrentEventID));
+}
+
+extern "C" void __def_use_trace_store(uint64_t Address,
+ uint64_t Size) {
+ std::cerr << "STORE 0x" << std::hex << Address << " " << std::dec << Size << '\n';
+}
+
+extern "C" void __def_use_trace_load(uint64_t Address,
+ uint64_t Size) {
+ std::cerr << "LOAD 0x" << std::hex << Address << " " << std::dec << Size << '\n';
+}
>From 2ce68c4ec35ffda6ac13474222a4726f6b1a024d Mon Sep 17 00:00:00 2001
From: ag <glisanov.andrej at yandex.ru>
Date: Sun, 26 Jul 2026 19:20:47 +0300
Subject: [PATCH 14/21] track memmory def use instructions
---
llvm/tools/def-use-runtime/DefUseRuntime.cpp | 97 ++++++++++++++------
1 file changed, 69 insertions(+), 28 deletions(-)
diff --git a/llvm/tools/def-use-runtime/DefUseRuntime.cpp b/llvm/tools/def-use-runtime/DefUseRuntime.cpp
index b1948a81a6633..86d02bc43d197 100644
--- a/llvm/tools/def-use-runtime/DefUseRuntime.cpp
+++ b/llvm/tools/def-use-runtime/DefUseRuntime.cpp
@@ -1,50 +1,91 @@
#include <cstdint>
-#include <cstdio>
-#include <unordered_map>
-#include <iostream>
#include <iomanip>
+#include <iostream>
+#include <map>
+#include <utility>
+#include <unordered_map>
+
+namespace {
-static std::uint64_t NextEventID = 0;
-static std::uint64_t CurrentEventID = 0;
+uint64_t NextEventID = 0;
+uint64_t CurrentEventID = 0;
-static std::unordered_map<std::uint64_t, std::uint64_t> LastEvent;
+// Статический InstID -> последнее динамическое событие этой инструкции.
+std::unordered_map<uint64_t, uint64_t> LastEventByInstID;
-extern "C" void __def_use_trace_inst(std::uint64_t InstID) {
+// Пока учитываем только полное совпадение адреса и размера:
+//
+// (Address, Size) -> EventID последнего store.
+std::map<std::pair<uint64_t, uint64_t>, uint64_t> LastStoreEvent;
+
+} // namespace
+
+extern "C" void __def_use_trace_inst(uint64_t InstID) {
CurrentEventID = NextEventID++;
- std::fprintf(
- stderr,
- "EVENT %llu INST %llu\n",
- static_cast<unsigned long long>(CurrentEventID),
- static_cast<unsigned long long>(InstID));
+ LastEventByInstID[InstID] = CurrentEventID;
- LastEvent[InstID] = CurrentEventID;
+ std::cerr << "EVENT "
+ << CurrentEventID
+ << " INST "
+ << InstID
+ << '\n';
}
-extern "C" void __def_use_trace_ssa_use(std::uint64_t DefID) {
- auto It = LastEvent.find(DefID);
+extern "C" void __def_use_trace_ssa_use(uint64_t DefInstID) {
+ auto It = LastEventByInstID.find(DefInstID);
- if (It == LastEvent.end()) {
- std::fprintf(
- stderr,
- "MISSING DEF INST %llu\n",
- static_cast<unsigned long long>(DefID));
+ if (It == LastEventByInstID.end()) {
return;
}
- std::fprintf(
- stderr,
- "EDGE %llu -> %llu\n",
- static_cast<unsigned long long>(It->second),
- static_cast<unsigned long long>(CurrentEventID));
+ uint64_t DefEventID = It->second;
+
+ std::cerr << "EDGE "
+ << DefEventID
+ << " -> "
+ << CurrentEventID
+ << '\n';
}
extern "C" void __def_use_trace_store(uint64_t Address,
uint64_t Size) {
- std::cerr << "STORE 0x" << std::hex << Address << " " << std::dec << Size << '\n';
+ std::cerr << "STORE 0x"
+ << std::hex
+ << Address
+ << std::dec
+ << " "
+ << Size
+ << '\n';
+
+ std::pair<uint64_t, uint64_t> MemoryRange{Address, Size};
+
+ LastStoreEvent[MemoryRange] = CurrentEventID;
}
extern "C" void __def_use_trace_load(uint64_t Address,
uint64_t Size) {
- std::cerr << "LOAD 0x" << std::hex << Address << " " << std::dec << Size << '\n';
-}
+ std::cerr << "LOAD 0x"
+ << std::hex
+ << Address
+ << std::dec
+ << " "
+ << Size
+ << '\n';
+
+ std::pair<uint64_t, uint64_t> MemoryRange{Address, Size};
+
+ auto It = LastStoreEvent.find(MemoryRange);
+
+ if (It == LastStoreEvent.end()) {
+ return;
+ }
+
+ uint64_t StoreEventID = It->second;
+
+ std::cerr << "MEM_EDGE "
+ << StoreEventID
+ << " -> "
+ << CurrentEventID
+ << '\n';
+}
\ No newline at end of file
>From 4c7a599050b98985ead779ee8afe83ac67710861 Mon Sep 17 00:00:00 2001
From: ag <glisanov.andrej at yandex.ru>
Date: Sun, 26 Jul 2026 19:58:41 +0300
Subject: [PATCH 15/21] Add Clang flag for def use
---
clang/include/clang/Basic/CodeGenOptions.def | 3 ++-
clang/include/clang/Driver/Options.td | 7 ++++++-
clang/lib/CodeGen/BackendUtil.cpp | 4 ++++
clang/lib/Driver/ToolChains/Clang.cpp | 3 +++
4 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index 12808eb275fa4..fe47c34ab5702 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -99,7 +99,8 @@ ENUM_CODEGENOPT(EmbedBitcode, EmbedBitcodeKind, 2, Embed_Off)
ENUM_CODEGENOPT(InlineAsmDialect, InlineAsmDialectKind, 1, IAD_ATT)
CODEGENOPT(ForbidGuardVariables , 1, 0) ///< Issue errors if C++ guard variables
///< are required.
-CODEGENOPT(FunctionSections , 1, 0) ///< Set when -ffunction-sections is enabled.
+CODEGENOPT(FunctionSections , 1, 0)
+CODEGENOPT(InsertDefUse , 1, 0) ///< Enable dynamic def-use instrumentation. ///< Set when -ffunction-sections is enabled.
CODEGENOPT(BBAddrMap , 1, 0) ///< Set when -fbasic-block-address-map is enabled.
CODEGENOPT(InstrumentFunctions , 1, 0) ///< Set when -finstrument-functions is
///< enabled.
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 15f9ee75492e3..ec530a4bdd887 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -50,7 +50,6 @@ def NoArgumentUnused : OptionFlag;
// Unsupported - The option is unsupported, and the driver will reject command
// lines that use it.
def Unsupported : OptionFlag;
-
// Ignored - The option is unsupported, and the driver will silently ignore it.
def Ignored : OptionFlag;
@@ -4176,6 +4175,12 @@ defm zero_initialized_in_bss : BoolFOption<"zero-initialized-in-bss",
NegFlag<SetTrue, [], [ClangOption, CC1Option],
"Don't place zero initialized data in BSS">,
PosFlag<SetFalse>>;
+defm insert_def_use : BoolFOption<"insert-def-use",
+ CodeGenOpts<"InsertDefUse">, DefaultFalse,
+ PosFlag<SetTrue, [], [ClangOption, CC1Option],
+ "Enable dynamic def-use instrumentation">,
+ NegFlag<SetFalse>>;
+
defm function_sections : BoolFOption<"function-sections",
CodeGenOpts<"FunctionSections">, DefaultFalse,
PosFlag<SetTrue, [], [ClangOption, CC1Option],
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index e765bbf637a66..ff305bc33f7d5 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -69,6 +69,7 @@
#include "llvm/Transforms/Instrumentation/AddressSanitizerOptions.h"
#include "llvm/Transforms/Instrumentation/BoundsChecking.h"
#include "llvm/Transforms/Instrumentation/DataFlowSanitizer.h"
+#include "llvm/Transforms/Instrumentation/DefUseInstrumentation.h"
#include "llvm/Transforms/Instrumentation/GCOVProfiler.h"
#include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h"
#include "llvm/Transforms/Instrumentation/InstrProfiling.h"
@@ -1038,6 +1039,9 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
}
}
+ if (CodeGenOpts.InsertDefUse)
+ MPM.addPass(llvm::DefUseInstrumentationPass());
+
// Link against bitcodes supplied via the -mlink-builtin-bitcode option
if (CodeGenOpts.LinkBitcodePostopt)
MPM.addPass(LinkInModulesPass(BC));
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 8858c318aba7a..f73175356034c 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6197,6 +6197,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_separate_named_sections);
Args.addOptInFlag(CmdArgs, options::OPT_funique_internal_linkage_names,
options::OPT_fno_unique_internal_linkage_names);
+
+ Args.addOptInFlag(CmdArgs, options::OPT_finsert_def_use,
+ options::OPT_fno_insert_def_use);
Args.addOptInFlag(CmdArgs, options::OPT_funique_basic_block_section_names,
options::OPT_fno_unique_basic_block_section_names);
Args.addOptInFlag(CmdArgs, options::OPT_fconvergent_functions,
>From a7279239f188a98e14cb054c5b99d91ac455e2b4 Mon Sep 17 00:00:00 2001
From: ag <glisanov.andrej at yandex.ru>
Date: Sun, 26 Jul 2026 20:06:05 +0300
Subject: [PATCH 16/21] add linking def-use runtime
---
clang/lib/Driver/ToolChains/Gnu.cpp | 10 ++++++++++
clang/runtime/CMakeLists.txt | 2 ++
clang/runtime/def-use/CMakeLists.txt | 20 +++++++++++++++++++
.../runtime/def-use}/DefUseRuntime.cpp | 0
4 files changed, 32 insertions(+)
create mode 100644 clang/runtime/def-use/CMakeLists.txt
rename {llvm/tools/def-use-runtime => clang/runtime/def-use}/DefUseRuntime.cpp (100%)
diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp
index 5e9a655eaf824..9ffecee257e93 100644
--- a/clang/lib/Driver/ToolChains/Gnu.cpp
+++ b/clang/lib/Driver/ToolChains/Gnu.cpp
@@ -545,6 +545,16 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
addLinkerCompressDebugSectionsOption(ToolChain, Args, CmdArgs);
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
+ if (Args.hasFlag(options::OPT_finsert_def_use,
+ options::OPT_fno_insert_def_use, false)) {
+ std::string DefUseRuntimePath =
+ (llvm::Twine(llvm::sys::path::parent_path(D.Dir)) + "/" +
+ CLANG_INSTALL_LIBDIR_BASENAME + "/libDefUseRuntime.a")
+ .str();
+
+ CmdArgs.push_back(Args.MakeArgString(DefUseRuntimePath));
+ }
+
addHIPRuntimeLibArgs(ToolChain, C, Args, CmdArgs);
// The profile runtime also needs access to system libraries.
diff --git a/clang/runtime/CMakeLists.txt b/clang/runtime/CMakeLists.txt
index 65fcdc2868f03..7709619e073ba 100644
--- a/clang/runtime/CMakeLists.txt
+++ b/clang/runtime/CMakeLists.txt
@@ -2,6 +2,8 @@
include(ExternalProject)
+add_subdirectory(def-use)
+
set(known_subdirs
"libcxx"
)
diff --git a/clang/runtime/def-use/CMakeLists.txt b/clang/runtime/def-use/CMakeLists.txt
new file mode 100644
index 0000000000000..a73057e14f768
--- /dev/null
+++ b/clang/runtime/def-use/CMakeLists.txt
@@ -0,0 +1,20 @@
+add_library(DefUseRuntime STATIC
+ DefUseRuntime.cpp
+)
+
+set_target_properties(DefUseRuntime PROPERTIES
+ OUTPUT_NAME DefUseRuntime
+ ARCHIVE_OUTPUT_DIRECTORY "${LLVM_LIBRARY_OUTPUT_INTDIR}"
+ POSITION_INDEPENDENT_CODE ON
+ FOLDER "Clang/Runtime"
+)
+
+# При сборке clang автоматически собираем и runtime.
+if(TARGET clang)
+ add_dependencies(clang DefUseRuntime)
+endif()
+
+install(TARGETS DefUseRuntime
+ ARCHIVE DESTINATION "lib${LLVM_LIBDIR_SUFFIX}"
+ COMPONENT DefUseRuntime
+)
diff --git a/llvm/tools/def-use-runtime/DefUseRuntime.cpp b/clang/runtime/def-use/DefUseRuntime.cpp
similarity index 100%
rename from llvm/tools/def-use-runtime/DefUseRuntime.cpp
rename to clang/runtime/def-use/DefUseRuntime.cpp
>From a886a17a2afb41f59753c9eae0e906005238579f Mon Sep 17 00:00:00 2001
From: ag <glisanov.andrej at yandex.ru>
Date: Sun, 26 Jul 2026 23:55:07 +0300
Subject: [PATCH 17/21] added unique IDs in diffenent modules
---
clang/runtime/def-use/DefUseRuntime.cpp | 27 ++++++++------
.../Instrumentation/DefUseInstrumentation.h | 35 +++++++++++++++----
2 files changed, 46 insertions(+), 16 deletions(-)
diff --git a/clang/runtime/def-use/DefUseRuntime.cpp b/clang/runtime/def-use/DefUseRuntime.cpp
index 86d02bc43d197..881a8432ba7f8 100644
--- a/clang/runtime/def-use/DefUseRuntime.cpp
+++ b/clang/runtime/def-use/DefUseRuntime.cpp
@@ -10,32 +10,39 @@ namespace {
uint64_t NextEventID = 0;
uint64_t CurrentEventID = 0;
-// Статический InstID -> последнее динамическое событие этой инструкции.
-std::unordered_map<uint64_t, uint64_t> LastEventByInstID;
+// Теперь инструкция определяется парой ModuleToken, InstID -> последнее динамическое событие.
+std::map<std::pair<uint64_t, uint64_t>, uint64_t>
+ LastEventByInstruction;
-// Пока учитываем только полное совпадение адреса и размера:
-//
// (Address, Size) -> EventID последнего store.
-std::map<std::pair<uint64_t, uint64_t>, uint64_t> LastStoreEvent;
+std::map<std::pair<uint64_t, uint64_t>, uint64_t>
+ LastStoreEvent;
} // namespace
-extern "C" void __def_use_trace_inst(uint64_t InstID) {
+extern "C" void __def_use_trace_inst(uint64_t ModuleToken,
+ uint64_t InstID) {
CurrentEventID = NextEventID++;
- LastEventByInstID[InstID] = CurrentEventID;
+ LastEventByInstruction[{ModuleToken, InstID}] = CurrentEventID;
std::cerr << "EVENT "
<< CurrentEventID
+ << " MODULE 0x"
+ << std::hex
+ << ModuleToken
+ << std::dec
<< " INST "
<< InstID
<< '\n';
}
-extern "C" void __def_use_trace_ssa_use(uint64_t DefInstID) {
- auto It = LastEventByInstID.find(DefInstID);
+extern "C" void __def_use_trace_ssa_use(uint64_t ModuleToken,
+ uint64_t DefInstID) {
+ auto It =
+ LastEventByInstruction.find({ModuleToken, DefInstID});
- if (It == LastEventByInstID.end()) {
+ if (It == LastEventByInstruction.end()) {
return;
}
diff --git a/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h b/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
index dc1ff9dff5f5e..a44832e2a6132 100644
--- a/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
+++ b/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
@@ -22,6 +22,7 @@
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Instructions.h"
+#include "llvm/IR/GlobalVariable.h"
#include <cstdint>
@@ -38,7 +39,7 @@ struct DefUseInstrumentationPass
DenseMap<Instruction*, uint64_t> InstIDs; // Мапа, для того чтоб повторный вызов инструкции вспоминался и айдишник ёё брался
SmallVector<Instruction *> Instructions; // Чтоб модуль заново не обходить, а по вектору пробежаться
- FunctionType* HookType = FunctionType::get(Type::getVoidTy(Ctx), {Type::getInt64Ty(Ctx)}, false);
+ FunctionType *HookType = FunctionType::get(Type::getVoidTy(Ctx),{Type::getInt64Ty(Ctx), Type::getInt64Ty(Ctx)}, false);
FunctionCallee Hook_inst = M.getOrInsertFunction("__def_use_trace_inst", HookType);
FunctionCallee Hook_use = M.getOrInsertFunction("__def_use_trace_ssa_use", HookType);
@@ -48,13 +49,35 @@ struct DefUseInstrumentationPass
const DataLayout &DL = M.getDataLayout(); // DataLayout::getTypeStoreSize() чтоб получить размер значения в памяти
+ GlobalVariable *ModuleTokenGV = M.getGlobalVariable("__def_use_module_token", true);
+
+ if (!ModuleTokenGV) {
+ ModuleTokenGV = new GlobalVariable(
+ M,
+ Type::getInt8Ty(Ctx),
+ false,
+ GlobalValue::InternalLinkage,
+ ConstantInt::get(Type::getInt8Ty(Ctx), 0),
+ "__def_use_module_token");
+ }
+
+ Constant *ModuleToken = ConstantExpr::getPtrToInt(ModuleTokenGV,Type::getInt64Ty(Ctx));
+
// первый обход заполняет мапу инструкция - ID
uint64_t CallID = 0;
for (Function &F : M) {
if (F.isDeclaration()) {
continue;
+ }
+
+ StringRef Name = F.getName();
+
+ if (Name.starts_with("__cxx_global_var_init") ||
+ Name.starts_with("_GLOBAL__sub_I_")) {
+ continue;
}
+
for (BasicBlock &BB : F) {
for (Instruction &I : BB) {
Instructions.push_back(&I);
@@ -68,7 +91,7 @@ struct DefUseInstrumentationPass
for (Instruction *I : Instructions) {
uint64_t UseID = InstIDs.lookup(I);
Builder.SetInsertPoint(I);
- Builder.CreateCall(Hook_inst, Builder.getInt64(UseID));
+ Builder.CreateCall(Hook_inst, {ModuleToken,Builder.getInt64(UseID)});
// Load и Store отельно обрабатываем
if (auto *LI = dyn_cast<LoadInst>(I)) {
@@ -85,7 +108,7 @@ struct DefUseInstrumentationPass
uint64_t Size = LoadSize.getFixedValue();
- Builder.CreateCall(HookLoad, {Address, Builder.getInt64(Size)});
+ Builder.CreateCall(HookLoad, { Address, Builder.getInt64(Size)});
} else if (auto *SI = dyn_cast<StoreInst>(I)) {
Value *PointerOperand = SI->getPointerOperand();
@@ -103,7 +126,7 @@ struct DefUseInstrumentationPass
uint64_t Size = StoreSize.getFixedValue();
- Builder.CreateCall(HookStore, {Address, Builder.getInt64(Size)});
+ Builder.CreateCall(HookStore, { Address, Builder.getInt64(Size)});
}
for (Use &Operand : I->operands()) {
@@ -113,14 +136,14 @@ struct DefUseInstrumentationPass
if (!Def) {
continue;
- }
+ }
if (!InstIDs.contains(Def))
continue;
uint64_t DefID = InstIDs.lookup(Def);
- Builder.CreateCall(Hook_use, Builder.getInt64(DefID));
+ Builder.CreateCall(Hook_use, {ModuleToken, Builder.getInt64(DefID)});
errs() << "DEF " << DefID <<
"-> USE " << UseID << "\n";
>From 0e1f8f771d945af0286ca1b4a5cee488ad611839 Mon Sep 17 00:00:00 2001
From: ag <glisanov.andrej at yandex.ru>
Date: Mon, 27 Jul 2026 00:36:42 +0300
Subject: [PATCH 18/21] Write dynamic def-use trace to file
---
clang/runtime/def-use/DefUseRuntime.cpp | 32 +++++++++++++++++++++----
1 file changed, 27 insertions(+), 5 deletions(-)
diff --git a/clang/runtime/def-use/DefUseRuntime.cpp b/clang/runtime/def-use/DefUseRuntime.cpp
index 881a8432ba7f8..8c4a56ca7b24a 100644
--- a/clang/runtime/def-use/DefUseRuntime.cpp
+++ b/clang/runtime/def-use/DefUseRuntime.cpp
@@ -4,6 +4,8 @@
#include <map>
#include <utility>
#include <unordered_map>
+#include <cstdlib>
+#include <fstream>
namespace {
@@ -18,6 +20,26 @@ std::map<std::pair<uint64_t, uint64_t>, uint64_t>
std::map<std::pair<uint64_t, uint64_t>, uint64_t>
LastStoreEvent;
+
+std::ostream &Trace() {
+ struct TraceOutput {
+ std::ofstream File;
+
+ TraceOutput() {
+ const char *Path = std::getenv("DEF_USE_TRACE");
+ File.open(Path ? Path : "defuse.trace");
+ }
+ };
+
+ static TraceOutput Output;
+
+ if (!Output.File.is_open()) {
+ return std::cerr;
+ }
+
+ return Output.File;
+}
+
} // namespace
extern "C" void __def_use_trace_inst(uint64_t ModuleToken,
@@ -26,7 +48,7 @@ extern "C" void __def_use_trace_inst(uint64_t ModuleToken,
LastEventByInstruction[{ModuleToken, InstID}] = CurrentEventID;
- std::cerr << "EVENT "
+ Trace() << "EVENT "
<< CurrentEventID
<< " MODULE 0x"
<< std::hex
@@ -48,7 +70,7 @@ extern "C" void __def_use_trace_ssa_use(uint64_t ModuleToken,
uint64_t DefEventID = It->second;
- std::cerr << "EDGE "
+ Trace() << "EDGE "
<< DefEventID
<< " -> "
<< CurrentEventID
@@ -57,7 +79,7 @@ extern "C" void __def_use_trace_ssa_use(uint64_t ModuleToken,
extern "C" void __def_use_trace_store(uint64_t Address,
uint64_t Size) {
- std::cerr << "STORE 0x"
+ Trace() << "STORE 0x"
<< std::hex
<< Address
<< std::dec
@@ -72,7 +94,7 @@ extern "C" void __def_use_trace_store(uint64_t Address,
extern "C" void __def_use_trace_load(uint64_t Address,
uint64_t Size) {
- std::cerr << "LOAD 0x"
+ Trace() << "LOAD 0x"
<< std::hex
<< Address
<< std::dec
@@ -90,7 +112,7 @@ extern "C" void __def_use_trace_load(uint64_t Address,
uint64_t StoreEventID = It->second;
- std::cerr << "MEM_EDGE "
+ Trace() << "MEM_EDGE "
<< StoreEventID
<< " -> "
<< CurrentEventID
>From c62748ff1113537f742ed88a077b76ec6e3d1aba Mon Sep 17 00:00:00 2001
From: ag <glisanov.andrej at yandex.ru>
Date: Mon, 27 Jul 2026 01:22:06 +0300
Subject: [PATCH 19/21] Added def use tracing in dot file
---
.../Instrumentation/DefUseInstrumentation.h | 5 +
llvm/tools/def-use-to-dot/CMakeLists.txt | 3 +
llvm/tools/def-use-to-dot/DefUseToDot.cpp | 216 ++++++++++++++++++
3 files changed, 224 insertions(+)
create mode 100644 llvm/tools/def-use-to-dot/CMakeLists.txt
create mode 100644 llvm/tools/def-use-to-dot/DefUseToDot.cpp
diff --git a/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h b/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
index a44832e2a6132..59d49e71a39f2 100644
--- a/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
+++ b/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
@@ -89,6 +89,9 @@ struct DefUseInstrumentationPass
// второй обход создает зависимости, на основе мапы, использует ли функция результат уже другой инструкции
for (Instruction *I : Instructions) {
+ if (isa<PHINode>(I)) { //phi функции скипаем, реализации нет
+ continue;
+ }
uint64_t UseID = InstIDs.lookup(I);
Builder.SetInsertPoint(I);
Builder.CreateCall(Hook_inst, {ModuleToken,Builder.getInt64(UseID)});
@@ -129,6 +132,8 @@ struct DefUseInstrumentationPass
Builder.CreateCall(HookStore, { Address, Builder.getInt64(Size)});
}
+
+ // проверка операнда, что это именно mul/plus и др, и установление связи def - use
for (Use &Operand : I->operands()) {
Value *V = Operand.get();
diff --git a/llvm/tools/def-use-to-dot/CMakeLists.txt b/llvm/tools/def-use-to-dot/CMakeLists.txt
new file mode 100644
index 0000000000000..e8dd8ba59a7bf
--- /dev/null
+++ b/llvm/tools/def-use-to-dot/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_llvm_tool(def-use-to-dot
+ DefUseToDot.cpp
+)
diff --git a/llvm/tools/def-use-to-dot/DefUseToDot.cpp b/llvm/tools/def-use-to-dot/DefUseToDot.cpp
new file mode 100644
index 0000000000000..8358c6dd701d8
--- /dev/null
+++ b/llvm/tools/def-use-to-dot/DefUseToDot.cpp
@@ -0,0 +1,216 @@
+#include <cstdint>
+#include <fstream>
+#include <iostream>
+#include <map>
+#include <optional>
+#include <sstream>
+#include <string>
+#include <vector>
+
+struct Event {
+ uint64_t ID;
+ std::string Module;
+ uint64_t InstID;
+ std::vector<std::string> Details;
+};
+
+struct Edge {
+ uint64_t From;
+ uint64_t To;
+ bool IsMemory;
+};
+
+static std::string escapeDotString(const std::string &Text) {
+ std::string Result;
+
+ for (char C : Text) {
+ if (C == '\\' || C == '"') {
+ Result += '\\';
+ }
+
+ Result += C;
+ }
+
+ return Result;
+}
+
+int main(int argc, char **argv) {
+ if (argc != 2 && argc != 4) {
+ std::cerr
+ << "Usage: " << argv[0]
+ << " <trace-file> [-o <dot-file>]\n";
+ return 1;
+ }
+
+ std::string InputPath = argv[1];
+ std::string OutputPath = "graph.dot";
+
+ if (argc == 4) {
+ if (std::string(argv[2]) != "-o") {
+ std::cerr << "Expected -o before output filename\n";
+ return 1;
+ }
+
+ OutputPath = argv[3];
+ }
+
+ std::ifstream Input(InputPath);
+
+ if (!Input.is_open()) {
+ std::cerr << "Could not open input file: "
+ << InputPath << '\n';
+ return 1;
+ }
+
+ std::map<uint64_t, Event> Events;
+ std::vector<Edge> Edges;
+ std::optional<uint64_t> CurrentEventID;
+
+ std::string Line;
+
+ while (std::getline(Input, Line)) {
+ if (Line.empty()) {
+ continue;
+ }
+
+ std::istringstream LineStream(Line);
+ std::string RecordType;
+
+ LineStream >> RecordType;
+
+ if (RecordType == "EVENT") {
+ uint64_t EventID;
+ uint64_t InstID;
+ std::string ModuleWord;
+ std::string Module;
+ std::string InstWord;
+
+ if (!(LineStream >> EventID
+ >> ModuleWord
+ >> Module
+ >> InstWord
+ >> InstID)) {
+ std::cerr << "Invalid EVENT line: "
+ << Line << '\n';
+ return 1;
+ }
+
+ if (ModuleWord != "MODULE" ||
+ InstWord != "INST") {
+ std::cerr << "Invalid EVENT format: "
+ << Line << '\n';
+ return 1;
+ }
+
+ Events[EventID] =
+ Event{EventID, Module, InstID, {}};
+
+ CurrentEventID = EventID;
+
+ } else if (RecordType == "EDGE" ||
+ RecordType == "MEM_EDGE") {
+ uint64_t From;
+ uint64_t To;
+ std::string Arrow;
+
+ if (!(LineStream >> From >> Arrow >> To) ||
+ Arrow != "->") {
+ std::cerr << "Invalid edge line: "
+ << Line << '\n';
+ return 1;
+ }
+
+ Edges.push_back(
+ Edge{From, To, RecordType == "MEM_EDGE"});
+
+ } else if (RecordType == "STORE" ||
+ RecordType == "LOAD") {
+ std::string Address;
+ uint64_t Size;
+
+ if (!(LineStream >> Address >> Size)) {
+ std::cerr << "Invalid memory line: "
+ << Line << '\n';
+ return 1;
+ }
+
+ if (!CurrentEventID.has_value()) {
+ std::cerr
+ << "Memory operation without preceding EVENT: "
+ << Line << '\n';
+ return 1;
+ }
+
+ auto EventIt = Events.find(*CurrentEventID);
+
+ if (EventIt == Events.end()) {
+ std::cerr << "Current event was not found\n";
+ return 1;
+ }
+
+ std::ostringstream Detail;
+
+ Detail << RecordType
+ << " " << Address
+ << " size=" << Size;
+
+ EventIt->second.Details.push_back(Detail.str());
+
+ } else {
+ std::cerr << "Unknown trace record: "
+ << Line << '\n';
+ return 1;
+ }
+ }
+
+ std::ofstream Output(OutputPath);
+
+ if (!Output.is_open()) {
+ std::cerr << "Could not open output file: "
+ << OutputPath << '\n';
+ return 1;
+ }
+
+ Output << "digraph DefUse {\n";
+ Output << " rankdir=TB;\n";
+ Output << " node [shape=box, fontname=\"monospace\"];\n";
+ Output << " edge [fontname=\"monospace\"];\n\n";
+
+ for (const auto &[EventID, EventData] : Events) {
+ std::ostringstream Label;
+
+ Label << "Event " << EventData.ID
+ << "\\nModule " << EventData.Module
+ << "\\nInst " << EventData.InstID;
+
+ for (const std::string &Detail : EventData.Details) {
+ Label << "\\n" << Detail;
+ }
+
+ Output << " n" << EventID
+ << " [label=\""
+ << escapeDotString(Label.str())
+ << "\"];\n";
+ }
+
+ Output << '\n';
+
+ for (const Edge &GraphEdge : Edges) {
+ Output << " n" << GraphEdge.From
+ << " -> n" << GraphEdge.To;
+
+ if (GraphEdge.IsMemory) {
+ Output << " [label=\"memory\", style=dashed]";
+ }
+
+ Output << ";\n";
+ }
+
+ Output << "}\n";
+
+ std::cout << "Wrote " << Events.size()
+ << " nodes and " << Edges.size()
+ << " edges to " << OutputPath << '\n';
+
+ return 0;
+}
>From 13b8ef62949444a84c6dddc92761b24b280f5e45 Mon Sep 17 00:00:00 2001
From: ag <glisanov.andrej at yandex.ru>
Date: Mon, 27 Jul 2026 01:28:01 +0300
Subject: [PATCH 20/21] Complete dynamic def-use graph generation
---
.../Instrumentation/DefUseInstrumentation.h | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h b/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
index 59d49e71a39f2..c3c0dd1851bb2 100644
--- a/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
+++ b/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
@@ -103,11 +103,11 @@ struct DefUseInstrumentationPass
Value *Address =
Builder.CreatePtrToInt(PointerOperand, Type::getInt64Ty(Ctx));
- errs() << "LOAD address value: " << *Address << '\n';
+ // errs() << "LOAD address value: " << *Address << '\n';
TypeSize LoadSize = DL.getTypeStoreSize(LI->getType());
- errs() << "Load size: " << LoadSize.getFixedValue() << '\n';
+ // errs() << "Load size: " << LoadSize.getFixedValue() << '\n';
uint64_t Size = LoadSize.getFixedValue();
@@ -119,12 +119,12 @@ struct DefUseInstrumentationPass
Value *Address =
Builder.CreatePtrToInt(PointerOperand, Type::getInt64Ty(Ctx));
- errs() << "Store address value: " << *Address << '\n';
+ // errs() << "Store address value: " << *Address << '\n';
Type *StoredType = SI->getValueOperand()->getType();
TypeSize StoreSize = DL.getTypeStoreSize(StoredType);
- errs() << "Store size: " << StoreSize.getFixedValue() << '\n';
+ // errs() << "Store size: " << StoreSize.getFixedValue() << '\n';
uint64_t Size = StoreSize.getFixedValue();
@@ -150,8 +150,8 @@ struct DefUseInstrumentationPass
Builder.CreateCall(Hook_use, {ModuleToken, Builder.getInt64(DefID)});
- errs() << "DEF " << DefID <<
- "-> USE " << UseID << "\n";
+ // errs() << "DEF " << DefID <<
+ // "-> USE " << UseID << "\n";
}
}
>From 854375c0e54fa7e722546730259454b1726d5206 Mon Sep 17 00:00:00 2001
From: ag <glisanov.andrej at yandex.ru>
Date: Mon, 27 Jul 2026 01:54:30 +0300
Subject: [PATCH 21/21] Move def use to source file
---
.../Instrumentation/DefUseInstrumentation.h | 153 +----------------
.../Transforms/Instrumentation/CMakeLists.txt | 1 +
.../Instrumentation/DefUseInstrumentation.cpp | 157 ++++++++++++++++++
3 files changed, 161 insertions(+), 150 deletions(-)
create mode 100644 llvm/lib/Transforms/Instrumentation/DefUseInstrumentation.cpp
diff --git a/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h b/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
index c3c0dd1851bb2..a138f7e5309db 100644
--- a/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
+++ b/llvm/include/llvm/Transforms/Instrumentation/DefUseInstrumentation.h
@@ -1,30 +1,7 @@
#ifndef LLVM_TRANSFORMS_INSTRUMENTATION_DEFUSEINSTRUMENTATION_H
#define LLVM_TRANSFORMS_INSTRUMENTATION_DEFUSEINSTRUMENTATION_H
-#include "llvm/ADT/StringRef.h"
-#include "llvm/IR/BasicBlock.h"
-#include "llvm/IR/Constant.h"
-#include "llvm/IR/Constants.h"
-#include "llvm/IR/DerivedTypes.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/IR/Function.h"
-#include "llvm/IR/Instruction.h"
-#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/PassManager.h"
-#include "llvm/IR/IRBuilder.h"
-#include "llvm/IR/Module.h"
-#include "llvm/IR/Type.h"
-#include "llvm/IR/Use.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/Transforms/IPO/SampleProfileProbe.h"
-
-
-#include "llvm/IR/DataLayout.h"
-#include "llvm/IR/Instructions.h"
-
-#include "llvm/IR/GlobalVariable.h"
-
-#include <cstdint>
namespace llvm {
@@ -32,133 +9,9 @@ class Module;
struct DefUseInstrumentationPass
: PassInfoMixin<DefUseInstrumentationPass> {
- PreservedAnalyses run(Module &M, ModuleAnalysisManager &) {
-
- LLVMContext& Ctx = M.getContext();
- IRBuilder<> Builder(Ctx);
- DenseMap<Instruction*, uint64_t> InstIDs; // Мапа, для того чтоб повторный вызов инструкции вспоминался и айдишник ёё брался
- SmallVector<Instruction *> Instructions; // Чтоб модуль заново не обходить, а по вектору пробежаться
-
- FunctionType *HookType = FunctionType::get(Type::getVoidTy(Ctx),{Type::getInt64Ty(Ctx), Type::getInt64Ty(Ctx)}, false);
- FunctionCallee Hook_inst = M.getOrInsertFunction("__def_use_trace_inst", HookType);
- FunctionCallee Hook_use = M.getOrInsertFunction("__def_use_trace_ssa_use", HookType);
-
- FunctionType *MemoryHookType = FunctionType::get(Type::getVoidTy(Ctx),{Type::getInt64Ty(Ctx), Type::getInt64Ty(Ctx)},false);
- FunctionCallee HookLoad = M.getOrInsertFunction("__def_use_trace_load", MemoryHookType);
- FunctionCallee HookStore = M.getOrInsertFunction("__def_use_trace_store", MemoryHookType);
-
- const DataLayout &DL = M.getDataLayout(); // DataLayout::getTypeStoreSize() чтоб получить размер значения в памяти
-
- GlobalVariable *ModuleTokenGV = M.getGlobalVariable("__def_use_module_token", true);
-
- if (!ModuleTokenGV) {
- ModuleTokenGV = new GlobalVariable(
- M,
- Type::getInt8Ty(Ctx),
- false,
- GlobalValue::InternalLinkage,
- ConstantInt::get(Type::getInt8Ty(Ctx), 0),
- "__def_use_module_token");
- }
-
- Constant *ModuleToken = ConstantExpr::getPtrToInt(ModuleTokenGV,Type::getInt64Ty(Ctx));
-
- // первый обход заполняет мапу инструкция - ID
- uint64_t CallID = 0;
-
- for (Function &F : M) {
- if (F.isDeclaration()) {
- continue;
- }
-
- StringRef Name = F.getName();
-
- if (Name.starts_with("__cxx_global_var_init") ||
- Name.starts_with("_GLOBAL__sub_I_")) {
- continue;
- }
-
- for (BasicBlock &BB : F) {
- for (Instruction &I : BB) {
- Instructions.push_back(&I);
- InstIDs[&I] = CallID;
- CallID++;
- }
- }
- }
- // второй обход создает зависимости, на основе мапы, использует ли функция результат уже другой инструкции
-
- for (Instruction *I : Instructions) {
- if (isa<PHINode>(I)) { //phi функции скипаем, реализации нет
- continue;
- }
- uint64_t UseID = InstIDs.lookup(I);
- Builder.SetInsertPoint(I);
- Builder.CreateCall(Hook_inst, {ModuleToken,Builder.getInt64(UseID)});
-
- // Load и Store отельно обрабатываем
- if (auto *LI = dyn_cast<LoadInst>(I)) {
- Value *PointerOperand = LI->getPointerOperand();
-
- Value *Address =
- Builder.CreatePtrToInt(PointerOperand, Type::getInt64Ty(Ctx));
-
- // errs() << "LOAD address value: " << *Address << '\n';
-
- TypeSize LoadSize = DL.getTypeStoreSize(LI->getType());
-
- // errs() << "Load size: " << LoadSize.getFixedValue() << '\n';
-
- uint64_t Size = LoadSize.getFixedValue();
-
- Builder.CreateCall(HookLoad, { Address, Builder.getInt64(Size)});
-
- } else if (auto *SI = dyn_cast<StoreInst>(I)) {
- Value *PointerOperand = SI->getPointerOperand();
-
- Value *Address =
- Builder.CreatePtrToInt(PointerOperand, Type::getInt64Ty(Ctx));
-
- // errs() << "Store address value: " << *Address << '\n';
-
- Type *StoredType = SI->getValueOperand()->getType();
- TypeSize StoreSize = DL.getTypeStoreSize(StoredType);
-
- // errs() << "Store size: " << StoreSize.getFixedValue() << '\n';
-
-
- uint64_t Size = StoreSize.getFixedValue();
-
- Builder.CreateCall(HookStore, { Address, Builder.getInt64(Size)});
- }
-
-
- // проверка операнда, что это именно mul/plus и др, и установление связи def - use
- for (Use &Operand : I->operands()) {
- Value *V = Operand.get();
-
- Instruction *Def = dyn_cast<Instruction>(V);
-
- if (!Def) {
- continue;
- }
-
- if (!InstIDs.contains(Def))
- continue;
-
- uint64_t DefID = InstIDs.lookup(Def);
-
- Builder.CreateCall(Hook_use, {ModuleToken, Builder.getInt64(DefID)});
-
- // errs() << "DEF " << DefID <<
- // "-> USE " << UseID << "\n";
- }
- }
-
- return PreservedAnalyses::none();
- }
- };
+ PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
+};
} // namespace llvm
-#endif // LLVM_TRANSFORMS_INSTRUMENTATION_DEFUSEINSTRUMENTATION_H
\ No newline at end of file
+#endif
\ No newline at end of file
diff --git a/llvm/lib/Transforms/Instrumentation/CMakeLists.txt b/llvm/lib/Transforms/Instrumentation/CMakeLists.txt
index 4e3f9e27e0c34..b165baf9b9ff1 100644
--- a/llvm/lib/Transforms/Instrumentation/CMakeLists.txt
+++ b/llvm/lib/Transforms/Instrumentation/CMakeLists.txt
@@ -4,6 +4,7 @@ add_llvm_component_library(LLVMInstrumentation
CGProfile.cpp
ControlHeightReduction.cpp
DataFlowSanitizer.cpp
+ DefUseInstrumentation.cpp
GCOVProfiling.cpp
BlockCoverageInference.cpp
MemProfiler.cpp
diff --git a/llvm/lib/Transforms/Instrumentation/DefUseInstrumentation.cpp b/llvm/lib/Transforms/Instrumentation/DefUseInstrumentation.cpp
new file mode 100644
index 0000000000000..b0c3d4ce0cf2a
--- /dev/null
+++ b/llvm/lib/Transforms/Instrumentation/DefUseInstrumentation.cpp
@@ -0,0 +1,157 @@
+#include "llvm/Transforms/Instrumentation/DefUseInstrumentation.h"
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/Constant.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Instruction.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/PassManager.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Type.h"
+#include "llvm/IR/Use.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Transforms/IPO/SampleProfileProbe.h"
+
+
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Instructions.h"
+
+#include "llvm/IR/GlobalVariable.h"
+
+#include <cstdint>
+
+namespace llvm {
+
+PreservedAnalyses
+DefUseInstrumentationPass::run(Module &M, ModuleAnalysisManager &) {
+
+ LLVMContext& Ctx = M.getContext();
+ IRBuilder<> Builder(Ctx);
+ DenseMap<Instruction*, uint64_t> InstIDs; // Мапа, для того чтоб повторный вызов инструкции вспоминался и айдишник ёё брался
+ SmallVector<Instruction *> Instructions; // Чтоб модуль заново не обходить, а по вектору пробежаться
+
+ FunctionType *HookType = FunctionType::get(Type::getVoidTy(Ctx),{Type::getInt64Ty(Ctx), Type::getInt64Ty(Ctx)}, false);
+ FunctionCallee Hook_inst = M.getOrInsertFunction("__def_use_trace_inst", HookType);
+ FunctionCallee Hook_use = M.getOrInsertFunction("__def_use_trace_ssa_use", HookType);
+
+ FunctionType *MemoryHookType = FunctionType::get(Type::getVoidTy(Ctx),{Type::getInt64Ty(Ctx), Type::getInt64Ty(Ctx)},false);
+ FunctionCallee HookLoad = M.getOrInsertFunction("__def_use_trace_load", MemoryHookType);
+ FunctionCallee HookStore = M.getOrInsertFunction("__def_use_trace_store", MemoryHookType);
+
+ const DataLayout &DL = M.getDataLayout(); // DataLayout::getTypeStoreSize() чтоб получить размер значения в памяти
+
+ GlobalVariable *ModuleTokenGV = M.getGlobalVariable("__def_use_module_token", true);
+
+ if (!ModuleTokenGV) {
+ ModuleTokenGV = new GlobalVariable(
+ M,
+ Type::getInt8Ty(Ctx),
+ false,
+ GlobalValue::InternalLinkage,
+ ConstantInt::get(Type::getInt8Ty(Ctx), 0),
+ "__def_use_module_token");
+ }
+
+ Constant *ModuleToken = ConstantExpr::getPtrToInt(ModuleTokenGV,Type::getInt64Ty(Ctx));
+
+ // первый обход заполняет мапу инструкция - ID
+ uint64_t CallID = 0;
+
+ for (Function &F : M) {
+ if (F.isDeclaration()) {
+ continue;
+ }
+
+ StringRef Name = F.getName();
+
+ if (Name.starts_with("__cxx_global_var_init") ||
+ Name.starts_with("_GLOBAL__sub_I_")) {
+ continue;
+ }
+
+ for (BasicBlock &BB : F) {
+ for (Instruction &I : BB) {
+ Instructions.push_back(&I);
+ InstIDs[&I] = CallID;
+ CallID++;
+ }
+ }
+ }
+ // второй обход создает зависимости, на основе мапы, использует ли функция результат уже другой инструкции
+
+ for (Instruction *I : Instructions) {
+ if (isa<PHINode>(I)) { //phi функции скипаем, реализации нет
+ continue;
+ }
+ uint64_t UseID = InstIDs.lookup(I);
+ Builder.SetInsertPoint(I);
+ Builder.CreateCall(Hook_inst, {ModuleToken,Builder.getInt64(UseID)});
+
+ // Load и Store отельно обрабатываем
+ if (auto *LI = dyn_cast<LoadInst>(I)) {
+ Value *PointerOperand = LI->getPointerOperand();
+
+ Value *Address =
+ Builder.CreatePtrToInt(PointerOperand, Type::getInt64Ty(Ctx));
+
+ // errs() << "LOAD address value: " << *Address << '\n';
+
+ TypeSize LoadSize = DL.getTypeStoreSize(LI->getType());
+
+ // errs() << "Load size: " << LoadSize.getFixedValue() << '\n';
+
+ uint64_t Size = LoadSize.getFixedValue();
+
+ Builder.CreateCall(HookLoad, { Address, Builder.getInt64(Size)});
+
+ } else if (auto *SI = dyn_cast<StoreInst>(I)) {
+ Value *PointerOperand = SI->getPointerOperand();
+
+ Value *Address =
+ Builder.CreatePtrToInt(PointerOperand, Type::getInt64Ty(Ctx));
+
+ // errs() << "Store address value: " << *Address << '\n';
+
+ Type *StoredType = SI->getValueOperand()->getType();
+ TypeSize StoreSize = DL.getTypeStoreSize(StoredType);
+
+ // errs() << "Store size: " << StoreSize.getFixedValue() << '\n';
+
+
+ uint64_t Size = StoreSize.getFixedValue();
+
+ Builder.CreateCall(HookStore, { Address, Builder.getInt64(Size)});
+ }
+
+
+ // проверка операнда, что это именно mul/plus и др, и установление связи def - use
+ for (Use &Operand : I->operands()) {
+ Value *V = Operand.get();
+
+ Instruction *Def = dyn_cast<Instruction>(V);
+
+ if (!Def) {
+ continue;
+ }
+
+ if (!InstIDs.contains(Def))
+ continue;
+
+ uint64_t DefID = InstIDs.lookup(Def);
+
+ Builder.CreateCall(Hook_use, {ModuleToken, Builder.getInt64(DefID)});
+
+ // errs() << "DEF " << DefID <<
+ // "-> USE " << UseID << "\n";
+ }
+ }
+
+ return PreservedAnalyses::none();
+}
+
+} // namespace llvm
More information about the llvm-branch-commits
mailing list