我有我用
foo.c
编译的程序clang -c -emit-llvm foo.c -o foo.bc
。它返回一个foo.bc
。
所以,我运行 opt -dot-cfg foo.bc
以获得 .dot
CFG。但是,我收到警告:
警告:您正在尝试打印位码文件。 这是不可取的,因为它可能会导致显示问题。如果 你真的想亲身体验 LLVM bitcode,你 可以使用
-f
选项强制输出。
如果我使用
-f
,我会得到一个不可读的文件。
更新
opt
的位码输出,与点输出无关。您可以使用 -disable-output
禁用位码输出或使用 -S
生成人类可读的 .ll
文件来抑制警告。clang
默认将优化级别设置为-O0
,因此每个功能都附加了optnone
属性,防止大多数优化过程运行该功能。opt
最近启用了新的通行证管理器(这里有解释,虽然有点过时),如果目标函数有optnone
,optional passes(IIUC,那些不影响功能)将自动跳过。
-dot-cfg
是可选通行证。所以你的函数有
optnone
attrubite 因为它是在 -O0
下编译的,而 CFGPrinter
跳过它,所以你没有得到任何点文件输出。
您有多种选择:
optnone
下禁用-O0
属性生成:clang -S -emit-llvm foo.c -o foo.ll -disable-O0-optnone
optnone
中的foo.ll
属性,并保存。opt
:opt -dot-cfg foo.ll -disable-output -enable-new-pm=0
注意:旧版通行证管理器确实尊重
optnone
属性,但它是通过在真正想要这样做的通行证中明确添加 skipFunction()
来完成的。 CFGPrinter
不处理 optnone
所以在遗留的通行证管理器管道中,点文件可以按预期转储。
顺便说一句,点输出将直接写入名称以
.
开头的文件(如果您没有为-cfg-dot-filename-prefix
指定opt
参数)。试试ls -a
!
见this
opt
实现细节:
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";
}
修复 Nuullll 的答案
clang -Xclang -disable-O0-optnone -S -emit-llvm foo.c -o foo.ll
需要在
-Xclang
前加上
-disable-O0-optnone
没有足够的代表评论 Null 的回答,但最近在 master 分支上更改了标志:
opt -dot-cfg foo.ll -disable-output -bugpoint-disable-legacy-pm=1