The def-use information can be extracted directly by Use . It is useful to identify the original allocated object, which helps to update the states in typestate problems, such as the file property simulation. The source code refer to tutorialpass/pass/FileSimulatorPass
int main() {
int a;
int b=10;
int c=10;
a=b+c;
return 0;
}
In LLVM IR compiled with -g
define dso_local i32 @main() #0 !dbg !7 {
entry:
%retval = alloca i32, align 4
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 0, i32* %retval, align 4
call void @llvm.dbg.declare(metadata i32* %a, metadata !11, metadata !DIExpression()), !dbg !12
call void @llvm.dbg.declare(metadata i32* %b, metadata !13, metadata !DIExpression()), !dbg !14
store i32 10, i32* %b, align 4, !dbg !14
call void @llvm.dbg.declare(metadata i32* %c, metadata !15, metadata !DIExpression()), !dbg !16
store i32 10, i32* %c, align 4, !dbg !16
%0 = load i32, i32* %b, align 4, !dbg !17
%1 = load i32, i32* %c, align 4, !dbg !18
%add = add nsw i32 %0, %1, !dbg !19
store i32 %add, i32* %a, align 4, !dbg !20
ret i32 0, !dbg !21
}
bool runOnFunction(Function &F){
errs() << "digraph " + F.getName() + "{\n";
errs() << "\n";
for (auto block = F.getBasicBlockList().begin(); block != F.getBasicBlockList().end(); block++) {
for (auto inst = block->begin(); inst != block->end(); inst++) {
for (Use &U:inst->operands()) {
Value *v = U.get();
if (dyn_cast<Instruction>(v)) {
errs() << "\"" << *dyn_cast<Instruction>(v) << "\"" << " -> " << "\"" << *inst << "\"" << ";\n";
}
}
}
}
errs() << "\n}\n";
}
The result is
" %retval = alloca i32, align 4" -> " store i32 0, i32* %retval, align 4"
" %b = alloca i32, align 4" -> " store i32 10, i32* %b, align 4, !dbg !14"
" %c = alloca i32, align 4" -> " store i32 10, i32* %c, align 4, !dbg !16"
" %b = alloca i32, align 4" -> " %0 = load i32, i32* %b, align 4, !dbg !17"
" %c = alloca i32, align 4" -> " %1 = load i32, i32* %c, align 4, !dbg !18"
" %0 = load i32, i32* %b, align 4, !dbg !17" -> " %add = add nsw i32 %0, %1, !dbg !19"
" %1 = load i32, i32* %c, align 4, !dbg !18" -> " %add = add nsw i32 %0, %1, !dbg !19"
" %add = add nsw i32 %0, %1, !dbg !19" -> " store i32 %add, i32* %a, align 4, !dbg !20"
" %a = alloca i32, align 4" -> " store i32 %add, i32* %a, align 4, !dbg !20"
For example, if we concerns about the data dependance of a at the statement a=b+c, we can track the def-use chain backward:
store i32 %add, i32* %a, align 4, !dbg !20
->
%add = add nsw i32 %0, %1, !dbg !19
->
%0 = load i32, i32* %b, align 4, !dbg !17
-> %b = alloca i32, align 4
%1 = load i32, i32* %c, align 4, !dbg !18
-> %c = alloca i32, align 4
The backward tracking ends until alloca is reached. b and c are the data dependency of a