如何将函数下的多个相同类型循环映射到LLVM IR中生成的基本块?
How to map multiple same type loops under a function to the generated basic block in LLVM IR?
如果循环是不同类型的,那么我可以很容易地用名称识别它们,但是如果有多个相同类型的循环(比如 5 while
循环),我如何识别LLVM IR对应源码中的哪个循环?
当我们按顺序访问代码和 LLVM IR 时,手动识别很容易,但我正在研究如何以编程方式识别它们。
例如,我在 C:
中有以下源代码
int main()
{
int count=1;
while (count <= 4)
{
count++;
}
while (count > 4)
{
count--;
}
return 0;
}
当我执行命令 clang -S -emit-llvm fileName.c
时,我 fileName.ll 创建了以下内容:
; ModuleID = 'abc.c'
source_filename = "abc.c"
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc19.0.23026"
; Function Attrs: noinline nounwind uwtable
define i32 @main() #0 {
entry:
%retval = alloca i32, align 4
%count = alloca i32, align 4
store i32 0, i32* %retval, align 4
store i32 1, i32* %count, align 4
br label %while.cond
while.cond: ; preds = %while.body, %entry
%0 = load i32, i32* %count, align 4
%cmp = icmp sle i32 %0, 4
br i1 %cmp, label %while.body, label %while.end
while.body: ; preds = %while.cond
%1 = load i32, i32* %count, align 4
%inc = add nsw i32 %1, 1
store i32 %inc, i32* %count, align 4
br label %while.cond
while.end: ; preds = %while.cond
br label %while.cond1
while.cond1: ; preds = %while.body3, %while.end
%2 = load i32, i32* %count, align 4
%cmp2 = icmp sgt i32 %2, 4
br i1 %cmp2, label %while.body3, label %while.end4
while.body3: ; preds = %while.cond1
%3 = load i32, i32* %count, align 4
%dec = add nsw i32 %3, -1
store i32 %dec, i32* %count, align 4
br label %while.cond1
while.end4: ; preds = %while.cond1
ret i32 0
}
attributes #0 = { noinline nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
!llvm.module.flags = !{!0}
!llvm.ident = !{!1}
!0 = !{i32 1, !"PIC Level", i32 2}
!1 = !{!"clang version 4.0.0 (tags/RELEASE_400/final)"}
现在为给定的源文件创建了两个基本块 while.cond
和 while.cond1
,我如何识别源代码中哪个基本块用于哪个 while 循环?
在我尝试回答之前,我只想注意,根据所选的优化级别或手动选择的 opt
通过,信息可能不存在或可能不准确(例如,由于内联、克隆等)。
现在,低级表示和源代码之间关联的方式是使用调试信息(例如 DWARF 格式)。要生成调试信息,您需要在编译期间使用 -g
命令行标志。
对于 LLVM IR,如果你看一下 Loop
API there are relevant calls like getStartLoc
。所以你可以做这样的事情(例如在 llvm::Function
pass 的 runOn
方法中):
llvm::SmallVector<llvm::Loop *> workList;
auto &LI = getAnalysis<llvm::LoopInfoWrapperPass>(CurFunc).getLoopInfo();
std::for_each(LI.begin(), LI.end(), [&workList](llvm::Loop *e) { workList.push_back(e); });
for(auto *e : workList) {
auto line = e->getStartLoc().getLine();
auto *scope = llvm::dyn_cast<llvm::DIScope>(e->getStartLoc().getScope());
auto filename = scope->getFilename();
// do stuff here
}
此外,对于BasicBlock
, you can also use the debug-related methods in Instruction
(e.g. getDebugLoc
) and combine it with calls to other Loop
的方法如getHeader
等
另外,请注意,有一个 getLoopID
方法为每个循环使用一个内部唯一 ID,但这并不总是存在,并且它受制于我在开始时提到的潜在省略。无论如何,如果您需要操作它,请按照 setLoopID
方法查看 LLVM 源代码中的示例(例如 lib/Transforms/Scalar/LoopRotation.cpp
)。
如果循环是不同类型的,那么我可以很容易地用名称识别它们,但是如果有多个相同类型的循环(比如 5 while
循环),我如何识别LLVM IR对应源码中的哪个循环?
当我们按顺序访问代码和 LLVM IR 时,手动识别很容易,但我正在研究如何以编程方式识别它们。
例如,我在 C:
中有以下源代码int main()
{
int count=1;
while (count <= 4)
{
count++;
}
while (count > 4)
{
count--;
}
return 0;
}
当我执行命令 clang -S -emit-llvm fileName.c
时,我 fileName.ll 创建了以下内容:
; ModuleID = 'abc.c'
source_filename = "abc.c"
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc19.0.23026"
; Function Attrs: noinline nounwind uwtable
define i32 @main() #0 {
entry:
%retval = alloca i32, align 4
%count = alloca i32, align 4
store i32 0, i32* %retval, align 4
store i32 1, i32* %count, align 4
br label %while.cond
while.cond: ; preds = %while.body, %entry
%0 = load i32, i32* %count, align 4
%cmp = icmp sle i32 %0, 4
br i1 %cmp, label %while.body, label %while.end
while.body: ; preds = %while.cond
%1 = load i32, i32* %count, align 4
%inc = add nsw i32 %1, 1
store i32 %inc, i32* %count, align 4
br label %while.cond
while.end: ; preds = %while.cond
br label %while.cond1
while.cond1: ; preds = %while.body3, %while.end
%2 = load i32, i32* %count, align 4
%cmp2 = icmp sgt i32 %2, 4
br i1 %cmp2, label %while.body3, label %while.end4
while.body3: ; preds = %while.cond1
%3 = load i32, i32* %count, align 4
%dec = add nsw i32 %3, -1
store i32 %dec, i32* %count, align 4
br label %while.cond1
while.end4: ; preds = %while.cond1
ret i32 0
}
attributes #0 = { noinline nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
!llvm.module.flags = !{!0}
!llvm.ident = !{!1}
!0 = !{i32 1, !"PIC Level", i32 2}
!1 = !{!"clang version 4.0.0 (tags/RELEASE_400/final)"}
现在为给定的源文件创建了两个基本块 while.cond
和 while.cond1
,我如何识别源代码中哪个基本块用于哪个 while 循环?
在我尝试回答之前,我只想注意,根据所选的优化级别或手动选择的 opt
通过,信息可能不存在或可能不准确(例如,由于内联、克隆等)。
现在,低级表示和源代码之间关联的方式是使用调试信息(例如 DWARF 格式)。要生成调试信息,您需要在编译期间使用 -g
命令行标志。
对于 LLVM IR,如果你看一下 Loop
API there are relevant calls like getStartLoc
。所以你可以做这样的事情(例如在 llvm::Function
pass 的 runOn
方法中):
llvm::SmallVector<llvm::Loop *> workList;
auto &LI = getAnalysis<llvm::LoopInfoWrapperPass>(CurFunc).getLoopInfo();
std::for_each(LI.begin(), LI.end(), [&workList](llvm::Loop *e) { workList.push_back(e); });
for(auto *e : workList) {
auto line = e->getStartLoc().getLine();
auto *scope = llvm::dyn_cast<llvm::DIScope>(e->getStartLoc().getScope());
auto filename = scope->getFilename();
// do stuff here
}
此外,对于BasicBlock
, you can also use the debug-related methods in Instruction
(e.g. getDebugLoc
) and combine it with calls to other Loop
的方法如getHeader
等
另外,请注意,有一个 getLoopID
方法为每个循环使用一个内部唯一 ID,但这并不总是存在,并且它受制于我在开始时提到的潜在省略。无论如何,如果您需要操作它,请按照 setLoopID
方法查看 LLVM 源代码中的示例(例如 lib/Transforms/Scalar/LoopRotation.cpp
)。