LLVM 不生成 CFG

LLVM doesn't generate CFG

我有我用 clang -c -emit-llvm foo.c -o foo.bc 编译的程序 foo.c。它return一个foo.bc。 所以,我 运行 opt -dot-cfg foo.bc 获得了 .dot CFG。但是,我收到警告:

警告:您正在尝试打印位码文件。 这是不可取的,因为它可能会导致显示问题。如果 你真的很想尝尝 LLVM bitcode first-hand,你 可以使用 -f 选项强制输出。

如果我使用 -f,我得到一个无法读取的文件。

更新

  1. WARNING是关于opt的位码输出,与点输出无关。您可以使用 -disable-output 禁用位码输出或使用 -S 生成人类可读的 .ll 文件来抑制警告。
  2. clang默认将优化级别设置为-O0,因此每个函数都附加了optnone attribute,防止大多数优化过程运行该函数。
  3. opt 最近启用了新的通行证管理器 (explanation here, a little outdated though),并且 可选通行证 (IIUC,这些不影响功能)将自动如果目标函数有 optnone.
  4. 则跳过
  5. -dot-cfg 是可选通行证。

所以你的函数有 optnone 属性,因为它是在 -O0 下编译的,CFGPrinter 跳过它,所以你没有得到任何点文件输出。

您有多种选择:

  1. -O0 下禁用 optnone 属性生成:
clang -S -emit-llvm foo.c -o foo.ll -disable-O0-optnone
  1. 手动删除 foo.ll 中的 optnone 属性,然后保存。
  2. 使用 opt 时切换回旧版通行证管理器:
opt -dot-cfg foo.ll -disable-output -enable-new-pm=0

注意:旧版通行证管理器确实尊重 optnone 属性,但它是通过在真正想要这样做的通行证中明确添加 skipFunction() 来完成的。 CFGPrinter 不处理 optnone 因此在旧版传递管理器管道中,可以按预期转储点文件。

顺便说一句,点输出将直接写入名称以 . 开头的文件(如果您没有为 opt 指定 -cfg-dot-filename-prefix 参数)。尝试 ls -a!

有关 opt 实施细节,请参见 this

static void writeCFGToDotFile(Function &F, BlockFrequencyInfo *BFI,
                              BranchProbabilityInfo *BPI, uint64_t MaxFreq,
                              bool CFGOnly = false) {
  std::string Filename =
      (CFGDotFilenamePrefix + "." + F.getName() + ".dot").str();
  errs() << "Writing '" << Filename << "'...";

  std::error_code EC;
  raw_fd_ostream File(Filename, EC, sys::fs::OF_Text);

  DOTFuncInfo CFGInfo(&F, BFI, BPI, MaxFreq);
  CFGInfo.setHeatColors(ShowHeatColors);
  CFGInfo.setEdgeWeights(ShowEdgeWeight);
  CFGInfo.setRawEdgeWeights(UseRawEdgeWeight);

  if (!EC)
    WriteGraph(File, &CFGInfo, CFGOnly);
  else
    errs() << "  error opening file for writing!";
  errs() << "\n";
}