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
,我得到一个无法读取的文件。
更新
- WARNING是关于
opt
的位码输出,与点输出无关。您可以使用 -disable-output
禁用位码输出或使用 -S
生成人类可读的 .ll
文件来抑制警告。
clang
默认将优化级别设置为-O0
,因此每个函数都附加了optnone
attribute,防止大多数优化过程运行该函数。
opt
最近启用了新的通行证管理器 (explanation here, a little outdated though),并且 可选通行证 (IIUC,这些不影响功能)将自动如果目标函数有 optnone
. 则跳过
-dot-cfg
是可选通行证。
所以你的函数有 optnone
属性,因为它是在 -O0
下编译的,CFGPrinter
跳过它,所以你没有得到任何点文件输出。
您有多种选择:
- 在
-O0
下禁用 optnone
属性生成:
clang -S -emit-llvm foo.c -o foo.ll -disable-O0-optnone
- 手动删除
foo.ll
中的 optnone
属性,然后保存。
- 使用
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";
}
我有我用 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
,我得到一个无法读取的文件。
更新
- WARNING是关于
opt
的位码输出,与点输出无关。您可以使用-disable-output
禁用位码输出或使用-S
生成人类可读的.ll
文件来抑制警告。 clang
默认将优化级别设置为-O0
,因此每个函数都附加了optnone
attribute,防止大多数优化过程运行该函数。opt
最近启用了新的通行证管理器 (explanation here, a little outdated though),并且 可选通行证 (IIUC,这些不影响功能)将自动如果目标函数有optnone
. 则跳过
-dot-cfg
是可选通行证。
所以你的函数有 optnone
属性,因为它是在 -O0
下编译的,CFGPrinter
跳过它,所以你没有得到任何点文件输出。
您有多种选择:
- 在
-O0
下禁用optnone
属性生成:
clang -S -emit-llvm foo.c -o foo.ll -disable-O0-optnone
- 手动删除
foo.ll
中的optnone
属性,然后保存。 - 使用
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";
}