遍历LLVM操作数

5-t*_*o-9 7 llvm llvm-ir llvm-c++-api

使用ModulePass,我的目标是向上遍历一个SSA图:从一个带有0..2个操作数的语句(大多数操作码都属于那个),我想找出两件事:

  1. 操作数是元数据/常量(简单:只是尝试转换为常量类型)还是变量?
  2. 如果它是一个变量,请告诉我定义它的语句(因为LLVM IR是SSA形式,这是一个格式正确的查询),所以我可以递归地继续这个遍历.

例如,假设遵循LLVM IR:

define i32 @mul_add(i32 %x, i32 %y, i32 %z) {
entry:
  %tmp = mul i32 %x, %y
  %tmp2 = add i32 %tmp, %z
  ret i32 %tmp2
}
Run Code Online (Sandbox Code Playgroud)

我将从return语句开始.现在我想知道我要回来的东西:

  1. 我将获得返回声明的操作数
  2. 我检测到操作数是一个名为%tmp2的变量
  3. 我将获得自定义%tmp2的语句的操作数
  4. 我将首先遍历第一个操作数%tmp
  5. (......)
  6. %x是一个函数参数,因此可能是遍历的结束(或者是?)
  7. (...继续本DFS中的其他分支......)

我如何使用C++ API来实现这些步骤?

5-t*_*o-9 2

解决方案很简单,我将尽可能通用地描述它。

LLVM 中的每个Operandanllvm::Instruction都是 supertype llvm::Value。的一个子类型Valuellvm::Instruction. 这允许通过以下方法进行递归:

bool runOnInstruction(llvm::Instruction *instruction) {
  bool flag = false;
  for (auto operand = instruction->operands().begin();
            operand != instruction->operands().end(); ++operand) {
    printOperandStats(operand->get());
    flag = runOnOperand(operand->get()) | flag;
  }
  return flag;
}

bool runOnOperand(llvm::Value *operand) {
  operand->printAsOperand(errs(), true);
  // ... do something else ... 
  auto *instruction = dyn_cast<llvm::Instruction>(operand);
  if (nullptr != instruction) {
    return runOnInstruction(instruction);
  } else {
    return false;
  }
}
Run Code Online (Sandbox Code Playgroud)

这等于问题所要求的 DFS。每个操作数将被转换为指令并被递归分析。布尔返回值通常用于 LLVM Passes:true 值描述对 IR 的修改。