llvm::User
(例如指令)的操作数为llvm::Value
s。
mem2reg 传递后,变量位于SSA form,其原始源代码对应的名称将丢失。 Value::getName()
只适用于某些事情;对于大多数变量,它们都是中介,它没有设置。
可以运行 instnamer 传递以提供所有变量名称,例如 tmp1 和 tmp2 ,但这不会捕获它们最初的位置来自。这是原始C代码旁边的一些LLVM IR:
我正在构建一个简单的html页面来可视化和调试我正在进行的一些优化,并且我想将SSA变量显示为 name ver 表示法,而不是只是临时的instnamer名称。它只是为了帮助我的可读性。
我从命令行中获取我的LLVM IR,如:
clang -g3 -O1 -emit-llvm -o test.bc -c test.c
IR中有llvm.dbg.declare
和llvm.dbg.value
的来电;你如何变成原始的源代码名称和SSA版本号?
那么如何从llvm::Value
确定原始变量(或命名常量名称)?调试器必须能够这样做,所以我该怎么办?
答案 0 :(得分:12)
这是以元数据形式附加到LLVM IR的调试信息的一部分。文档is here。一篇旧博客文章,背景为is also available。
$ cat > z.c
long fact(long arg, long farg, long bart)
{
long foo = farg + bart;
return foo * arg;
}
$ clang -emit-llvm -O3 -g -c z.c
$ llvm-dis z.bc -o -
产生这个:
define i64 @fact(i64 %arg, i64 %farg, i64 %bart) #0 {
entry:
tail call void @llvm.dbg.value(metadata !{i64 %arg}, i64 0, metadata !10), !dbg !17
tail call void @llvm.dbg.value(metadata !{i64 %farg}, i64 0, metadata !11), !dbg !17
tail call void @llvm.dbg.value(metadata !{i64 %bart}, i64 0, metadata !12), !dbg !17
%add = add nsw i64 %bart, %farg, !dbg !18
tail call void @llvm.dbg.value(metadata !{i64 %add}, i64 0, metadata !13), !dbg !18
%mul = mul nsw i64 %add, %arg, !dbg !19
ret i64 %mul, !dbg !19
}
使用-O0
代替-O3
,您将看不到llvm.dbg.value
,但您会看到llvm.dbg.declare
。
答案 1 :(得分:6)
给定Value
,从中获取变量名称可以通过遍历封闭函数中的所有llvm.dbg.declare
和llvm.dbg.value
调用来完成,检查是否有任何引用该值,以及是否因此,返回与该固有调用相关联的值DIVariable
。
因此,代码应该看起来像(粗略,未测试甚至编译):
const Function* findEnclosingFunc(const Value* V) {
if (const Argument* Arg = dyn_cast<Argument>(V)) {
return Arg->getParent();
}
if (const Instruction* I = dyn_cast<Instruction>(V)) {
return I->getParent()->getParent();
}
return NULL;
}
const MDNode* findVar(const Value* V, const Function* F) {
for (const_inst_iterator Iter = inst_begin(F), End = inst_end(F); Iter != End; ++Iter) {
const Instruction* I = &*Iter;
if (const DbgDeclareInst* DbgDeclare = dyn_cast<DbgDeclareInst>(I)) {
if (DbgDeclare->getAddress() == V) return DbgDeclare->getVariable();
} else if (const DbgValueInst* DbgValue = dyn_cast<DbgValueInst>(I)) {
if (DbgValue->getValue() == V) return DbgValue->getVariable();
}
}
return NULL;
}
StringRef getOriginalName(const Value* V) {
// TODO handle globals as well
const Function* F = findEnclosingFunc(V);
if (!F) return V->getName();
const MDNode* Var = findVar(V, F);
if (!Var) return "tmp";
return DIVariable(Var).getName();
}
你可以看到上面我懒得添加全局变量的处理,但实际上并不是那么大 - 这需要迭代当前编译单元调试信息下列出的所有全局变量(使用M.getNamedMetadata("llvm.dbg.cu")
来获取当前模块中所有编译单元的列表),然后检查哪些与您的变量匹配(通过getGlobal
方法)并返回其名称。
但是,请注意上述内容仅适用于与原始变量直接关联的值。任何计算结果的任何值都不会以这种方式正确命名;特别是,表示字段访问的值不会使用字段名称命名。这是可行的,但需要更多涉及的处理 - 您必须从GEP中识别字段编号,然后深入了解结构的类型调试信息以获取字段名称。调试器这样做,是的,但没有调试器在LLVM IR域中运行 - 据我所知,即使LLVM自己的LLDB工作方式也不同,方法是将目标文件中的DWARF解析为Clang类型。
答案 2 :(得分:0)
我有类似的要求,将IR转换为&#34; SSA变量为 VarName ver 符号&#34;。以下文档和链接帮助了我。 1)https://releases.llvm.org/3.4.2/docs/tutorial/LangImpl7.html 2)LLVM opt mem2reg has no effect
希望这有助于社区!!!
答案 3 :(得分:0)
如果您使用的是最新版本的Clang,则其他一些方法将不起作用。
相反,对