小源代码 adddd.c:
int adddddd(int a_a_a, int b_b_b)
{
return a_a_a + b_b_b;
}
1,clang 生成 AST
clang -cc1 -ast-dump adddd.c
2,clang 生成 LLVM IR
clang -S -emit-llvm adddd.c -o adddd.ll
3,clang opt 生成 CFG 图
summmm.c 源码:
int summ(int N_N_N)
{
int tmp = 0;
while(N_N_N>0)
{
tmp += N_N_N;
}
return tmp;
}
clang -S -emit-llvm summmm.c -o summmm.ll
opt -dot-cfg summmm.ll
生成 cfg.summ.dot 文件。
dot文件:
digraph "CFG for 'summ' function" {
label="CFG for 'summ' function";
Node0x6131151575d0 [shape=record,label="{entry:\l %N_N_N.addr = alloca i32, align 4\l %tmp = alloca i32, align 4\l store i32 %N_N_N, i32* %N_N_N.addr, align 4\l store i32 0, i32* %tmp, align 4\l br label %while.cond\l}"];
Node0x6131151575d0 -> Node0x613115167c30;
Node0x613115167c30 [shape=record,label="{while.cond: \l %0 = load i32* %N_N_N.addr, align 4\l %cmp = icmp sgt i32 %0, 0\l br i1 %cmp, label %while.body, label %while.end\l|{<s0>T|<s1>F}}"];
Node0x613115167c30:s0 -> Node0x613115166680;
Node0x613115167c30:s1 -> Node0x613115164590;
Node0x613115166680 [shape=record,label="{while.body: \l %1 = load i32* %N_N_N.addr, align 4\l %2 = load i32* %tmp, align 4\l %add = add nsw i32 %2, %1\l store i32 %add, i32* %tmp, align 4\l br label %while.cond\l}"];
Node0x613115166680 -> Node0x613115167c30;
Node0x613115164590 [shape=record,label="{while.end: \l %3 = load i32* %tmp, align 4\l ret i32 %3\l}"];
}
复制到浏览器左侧:
https://dreampuf.github.io/GraphvizOnline/?engine=dot
补充知识点:
CFG:以基本块为节点的有向图;
CFG的编译流程位置: 通常由对 IR 的分析而得到: Lang -> LLVM IR -> CFG
CFG 中的基本块的定义;
基本块的Leader 指令;
基本块的产生征兆;
基本块的结束条件;
基本块的确定;
CFG 的构造步骤;
4,
5,
6,
7,
8,
9,