LLVM操作数的遍历

Traversal of LLVM Operands

使用 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
}

我将从 return 语句开始。现在我想知道我在 returning:

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

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

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

LLVM 中 llvm::Instruction 的每个 Operand 都是超类型 llvm::ValueValue 的子类型是 llvm::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;
  }
}

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