1. 首先介绍测试用例,这是一个简单的if-then-else结构,输入为 int 类型的单变量,输出为 int 类型的结果。如果条件 a < 1 成立,则将输入直接返回;如果条件不成立,则返回 1。

int foo(int a) {
if (a < 1)
return a;
else
return 1;
}

2. 我们用GCC编译上述用例,打印出构造CFG之前的GIMPLE序列。在划分BB块之前,所有GIMPLE表达式在同一个序列中。

;; Function foo (foo, funcdef_no=0, decl_uid=1793, cgraph_uid=0, symbol_order=0)

foo (int a)
{
int D.1800; if (a <= 0) goto <D.1798>; else goto <D.1799>;
<D.1798>:
D.1800 = a;
goto <D.1801>;
<D.1799>:
D.1800 = 1;
goto <D.1801>;
<D.1801>:
return D.1800;
}

3. GIMPLE 序列是一段线性结构,以双向链表的形式保存。next指向下一条gimple表达式,prev指向上一条gimple表达式,label也是单独的一条gimple表达式。

(gdb) pt gimple_seq
type = struct gimple {
gimple_code code : 8;
unsigned int no_warning : 1;
unsigned int visited : 1;
unsigned int nontemporal_move : 1;
unsigned int plf : 2;
unsigned int modified : 1;
unsigned int has_volatile_ops : 1;
unsigned int pad : 1;
unsigned int subcode : 16;
unsigned int uid;
location_t location;
unsigned int num_ops;
basic_block bb;
gimple *next;
gimple *prev;
} * (gdb) p debug(seq)
if (a <= 0) goto <D.1798>; else goto <D.1799>;
(gdb) p debug(seq->next)
<D.1798>:
(gdb) p debug(seq->next->next)
D.1800 = a;
(gdb) p debug(seq->next->next->next)
goto <D.1801>;

4.  BB块构造算法:

4.1 顺序遍历GIMPLE序列,把正在访问的stmt 的bb属性设置为当前BB。如果 stmt 是 label,则建立 label -> bb 的 map 关系,便于在 make_edges 时快速查找到 label 所在的 bb。

4.2 如果遇到符合stmt_starts_bb_p 和stmt_ends_bb_p 条件的stmt,则创建一个新的BB。

/* Insert SEQ after BB and build a flowgraph.  */
static basic_block
make_blocks_1 (gimple_seq seq, basic_block bb)
{
gimple_stmt_iterator i = gsi_start (seq);
gimple *stmt = NULL;
bool start_new_block = true;
bool first_stmt_of_seq = true;
// 顺序遍历GIMPLE序列
while (!gsi_end_p (i))
{
gimple *prev_stmt;
prev_stmt = stmt;
stmt = gsi_stmt (i);
if (stmt && is_gimple_call (stmt))
gimple_call_initialize_ctrl_altering (stmt); /* If the statement starts a new basic block or if we have determined
in a previous pass that we need to create a new block for STMT, do
so now. */
if (start_new_block || stmt_starts_bb_p (stmt, prev_stmt))
{
if (!first_stmt_of_seq)
gsi_split_seq_before (&i, &seq);
bb = create_basic_block (seq, bb);
start_new_block = false;
}
/* Now add STMT to BB and create the subgraphs for special statement
codes. */
gimple_set_bb (stmt, bb);
/* If STMT is a basic block terminator, set START_NEW_BLOCK for the
next iteration. */
if (stmt_ends_bb_p (stmt))
{
……
start_new_block = true;
}
gsi_next (&i);
first_stmt_of_seq = false;
}
return bb;
}

5. 完成BB的构造后,编译器会遍历每个BB的最后一条stmt(带有目标BB的label信息),根据stmt的GIMPLE_CODE类型,调用不同接口建立BB之间的edges。此后,GIMPLE序列整体的组织方式发生了改变,由线性序列变成了以BB块为节点的图结构。在每个BB 的内部,GIMPLE表达式仍然以链表的形式线性保存。

;; Function foo (foo, funcdef_no=0, decl_uid=1793, cgraph_uid=0, symbol_order=0)

;; 1 loops found
;;
;; Loop 0
;; header 0, latch 1
;; depth 0, outer -1
;; nodes: 0 1 2 3 4 5
;; 2 succs { 3 4 }
;; 3 succs { 5 }
;; 4 succs { 5 }
;; 5 succs { 1 }
foo (int a)
{
int D.1800; <bb 2> [0.00%]:
if (a <= 0)
goto <bb 3>; [0.00%]
else
goto <bb 4>; [0.00%] <bb 3> [0.00%]:
D.1800 = a;
goto <bb 5> (<L2>); [0.00%] <bb 4> [0.00%]:
D.1800 = 1; <L2> [0.00%]:
return D.1800; }

【GCC编译器】将GIMPLE序列划分成基本块(Basic block),并构造控制流图的更多相关文章

  1. ZOJ 3963 Heap Partition set维护。给一个序列,将其划分成尽量少的序列,使每一个序列满足按照顺序构造二叉树,父母的值<=孩子的值。

    Heap Partition Time Limit: Seconds Memory Limit: KB Special Judge A sequence S = {s1, s2, ..., sn} i ...

  2. GCC编译器基础入门

    导语 GCC(GNU Compiler Collection,GNU 编译器套件) 是由 GNU 开发的编程语言编译器,支持C.C++.Objective-C.Fortran.Java.Ada和Go语 ...

  3. 字符编码与gcc 编译器的编码问题

    最近在 vscode 中借助 gcc 编译器来配置 c 语言开发环境时,发现中文编码存在乱码问题.再加上最近学习到多字节字符与宽字符,搅在一起,搞得很乱,就把自己的理解写下来,供有需者参考吧. 1. ...

  4. 利用GCC编译器生成动态链接库和静态链接库

    转载请标明:http://www.cnblogs.com/winifred-tang94/ 1.编译过程 gcc –fPIC –c xxx.c 其中-fPIC是通知gcc编译器产生位置独立的目标代码. ...

  5. GCC编译器编译链接

    在gcc编译器环境下,常见的文件扩展名的含义如下: .c:C源程序,经过预编译后的源程序也为.c文件,它可以通过-E参数输出. .h:头文件 .s:经过编译得到的汇编程序代码,它可以通过-S参数输出. ...

  6. GCC编译器使用

    一.GCC简介 通常所说的GCC是GUN Compiler Collection的简称,除了编译程序之外,它还含其他相关工具,所以它能把易于人类使用的高级语言编写的源代码构建成计算机能够直接执行的二进 ...

  7. GCC编译器和GDB调试器常用选项

    http://blog.csdn.net/u014328976/article/details/46745349 GCC编译器 gcc hello.c -o hello                 ...

  8. gcc编译器与基本类型3

    C语言发展史 1969年贝尔实验室 肯尼斯·蓝·汤普逊,丹尼斯·李奇开发了B语言 ->Unix,New B语言,改名C语言83年提出C语言标准 1989年十二月正式通过C语言标准,C89标准 C ...

  9. 如何使用gcc编译器

    开始... 首先,我们应该知道如何调用编译器.实际上,这很简单.我们将从那个著名的第一个C程序开始. #include <stdio.h> int main() { printf(&quo ...

随机推荐

  1. 深入理解 sync.Once 与 sync.Pool

    深入理解 sync.Once 与 sync.Pool sync.Once 代表在这个对象下在这个示例下多次执行能保证只会执行一次操作. var once sync.Once for i:=0; i & ...

  2. Binding(三):资源和ValueConverter

    这节讲资源和值转换器(ValueConverter). 资源 在XAML中,我们想要使用外部的数据或者类,需要引入其命名空间,然后将其定义为XAML页面的资源,供给控件使用,或者我们需要封装一个共用的 ...

  3. Springboot WebFlux集成Spring Security实现JWT认证

    我最新最全的文章都在南瓜慢说 www.pkslow.com,欢迎大家来喝茶! 1 简介 在之前的文章<Springboot集成Spring Security实现JWT认证>讲解了如何在传统 ...

  4. Golang控制子gorutine退出,并阻塞等待所有子gorutine全部退出

    Golang控制子gorutine退出,并阻塞等待所有子gorutine全部退出 需求 程序有时需要自动重启或者重新初始化一些功能,就需要退出之前的所有子gorutine,并且要等待所有子goruti ...

  5. 温故知新,CSharp遇见字符串比较(String Comparison),更佳科学的比较字符串

    背景 在C#中,我们经常会遇到需要比较字符串的场景,有时候甚至因为外部输入的不确定性,我们需要忽略大小写来进行比较,以达到判断业务的述求. 对字符串用法的建议 使用.NET进行开发时,请遵循以下简要建 ...

  6. CentOS-搭建MinIO集群

    一.基础环境 操作系统:CentOS 7.x Minio在线演示 Minio下载 二.准备工作 2.1.机器资源 192.168.1.101 /data1 192.168.1.102 /data2 1 ...

  7. C#/VB.NET 设置PDF跨页表格重复显示表头行

    在创建表格时,如果表格内容出现跨页显示的时候,默认情况下该表格的表头不会在下一页显示,在阅读体验上不是很好.下面分享一个方法如何在表格跨页时显示表格的表头内容,在C#中只需要简单使用方法grid.Re ...

  8. mysql 深度解析auto-increment自增列"Duliplicate key"问题

    转载自:https://cloud.tencent.com/developer/article/1367681 问题描述 近期,线上有个重要Mysql客户的表在从5.6升级到5.7后master上插入 ...

  9. 官宣.NET 6 预览版4

    我们很高兴发布 .NET 6 Preview 4.我们现在大约完成了 .NET 6 发布的一半.现在是一个很好的时机,可以再次查看.NET6的完整范围.许多功能都接近最终形式,而其他功能将很快推出,因 ...

  10. ADO.NET整理 [转]

    虽然我们都知道ADO.NET是对数据库的操作,但是要真的说出ADO.NET的具体含义还不是很容易. ADO.NET是ActiveX Data Objects的缩写,它是一个COM组件库,用于在micr ...