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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
