获取原始变量名称为LLVM价值

问题描述 投票:18回答:4

用于llvm::User(例如指令)的操作数都是llvm::Values。

在mem2reg通后,变量是SSA form,以及其作为与原来的源代码名称都将丢失。 Value::getName()只设置一些事情;对于大多数变量,这是中介机构,其未设置。

该instnamer通可以运行给所有的变量的名称,如TMP1和tmp2,但这并不能捕捉到他们最初来自。这里是原来的C代码旁边一些LLVM IR:

我建立一个简单的HTML页面可视化和调试的一些最佳化我的工作,我想显示SSA变量namever符号,而不仅仅是临时instnamer名。它只是帮助我的可读性。

我从一个命令行如铛让我LLVM IR:

 clang -g3 -O1 -emit-llvm -o test.bc -c test.c

有来电在IR至llvm.dbg.declarellvm.dbg.value;你怎么变成原来的源代码名称和SSA版本号?

所以,我怎么能确定从llvm::Value原始变量(或命名常量名)?调试器必须能够做到这一点,所以我怎么能?

compiler-construction clang llvm debug-symbols llvm-ir
4个回答
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


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的工作方式不同,由目标文件到锵类型解析侏儒。


1
投票

如果您使用的是最新的锵版本一些其他方法将无法正常工作。相反,使用-fno-丢弃值,名称标志铛。这将使LLVM ::值保持其原来的名称


0
投票

我也有类似的要求,转换成IR“SSA变量VarNamever符号”。下面的文件和链接帮助了我。 1)https://releases.llvm.org/3.4.2/docs/tutorial/LangImpl7.html 2)LLVM opt mem2reg has no effect

希望这有助于社区!

© www.soinside.com 2019 - 2024. All rights reserved.