Skip to content

Commit 01ed390

Browse files
committed
Add callgraph visualizer
1 parent 6ae4205 commit 01ed390

File tree

3 files changed

+77
-0
lines changed

3 files changed

+77
-0
lines changed

code/article_05/cg.ll

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
; cg.ll
2+
define void @foo1() {
3+
call void @foo4(i32 0)
4+
ret void
5+
}
6+
7+
declare void @foo2()
8+
declare void @foo3()
9+
10+
define void @foo4(i32 %0) {
11+
%comparison_result = icmp sgt i32 %0, 0
12+
br i1 %comparison_result, label %true_branch, label %false_branch
13+
14+
true_branch:
15+
call void @foo1()
16+
br label %final
17+
18+
false_branch:
19+
call void @foo2()
20+
br label %final
21+
22+
final:
23+
call void @foo3()
24+
ret void
25+
}

src/05-控制流/02-函数.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,58 @@ foo:
246246

247247
我们可以发现,在结尾,使用的是`jmp`而不是`call`,所以从高级语言的角度,就可以看作其将尾部的调用变成了循环。并且,有两个操作:`pushq %rax``popq %rax`。这两个操作只是为了栈对齐,具体可以参考stack overflow上的回答[Why does this function push RAX to the stack as the first operation?](https://stackoverflow.com/a/45823778/10005095)
248248

249+
## 可视化
250+
251+
与控制语句的可视化类似,我们也可以通过LLVM工具链,获得LLVM IR的函数调用图(Call Graph)。
252+
253+
假设我们有以下LLVM IR:
254+
255+
```llvm
256+
; cg.ll
257+
define void @foo1() {
258+
call void @foo4(i32 0)
259+
ret void
260+
}
261+
262+
declare void @foo2()
263+
declare void @foo3()
264+
265+
define void @foo4(i32 %0) {
266+
%comparison_result = icmp sgt i32 %0, 0
267+
br i1 %comparison_result, label %true_branch, label %false_branch
268+
269+
true_branch:
270+
call void @foo1()
271+
br label %final
272+
273+
false_branch:
274+
call void @foo2()
275+
br label %final
276+
277+
final:
278+
call void @foo3()
279+
ret void
280+
}
281+
```
282+
283+
`foo4`根据输入,调用`foo1`或者`foo2`,最终调用`foo3`。而`foo1`则递归调用`foo4`
284+
285+
对于这样的LLVM IR,我们使用
286+
287+
```shell
288+
opt -p dot-callgraph cg.ll
289+
```
290+
291+
可以生成一个`cg.ll.callgraph.dot`的文件。类似CFG,我们可以使用
292+
293+
```shell
294+
dot cg.ll -Tpng -o cg.png
295+
```
296+
297+
生成如下图所示的函数调用图:
298+
299+
![Call Graph](../assets/05_cg.png)
300+
249301
### 帧指针清除优化
250302

251303
最后,再讲一个函数调用中的优化,就是帧指针清除优化(Frame Pointer Elimination)。

src/assets/05_cg.png

7.46 KB
Loading

0 commit comments

Comments
 (0)