【GCC编译器】将GIMPLE序列划分成基本块(Basic block),并构造控制流图
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),并构造控制流图的更多相关文章
- ZOJ 3963 Heap Partition set维护。给一个序列,将其划分成尽量少的序列,使每一个序列满足按照顺序构造二叉树,父母的值<=孩子的值。
Heap Partition Time Limit: Seconds Memory Limit: KB Special Judge A sequence S = {s1, s2, ..., sn} i ...
- GCC编译器基础入门
导语 GCC(GNU Compiler Collection,GNU 编译器套件) 是由 GNU 开发的编程语言编译器,支持C.C++.Objective-C.Fortran.Java.Ada和Go语 ...
- 字符编码与gcc 编译器的编码问题
最近在 vscode 中借助 gcc 编译器来配置 c 语言开发环境时,发现中文编码存在乱码问题.再加上最近学习到多字节字符与宽字符,搅在一起,搞得很乱,就把自己的理解写下来,供有需者参考吧. 1. ...
- 利用GCC编译器生成动态链接库和静态链接库
转载请标明:http://www.cnblogs.com/winifred-tang94/ 1.编译过程 gcc –fPIC –c xxx.c 其中-fPIC是通知gcc编译器产生位置独立的目标代码. ...
- GCC编译器编译链接
在gcc编译器环境下,常见的文件扩展名的含义如下: .c:C源程序,经过预编译后的源程序也为.c文件,它可以通过-E参数输出. .h:头文件 .s:经过编译得到的汇编程序代码,它可以通过-S参数输出. ...
- GCC编译器使用
一.GCC简介 通常所说的GCC是GUN Compiler Collection的简称,除了编译程序之外,它还含其他相关工具,所以它能把易于人类使用的高级语言编写的源代码构建成计算机能够直接执行的二进 ...
- GCC编译器和GDB调试器常用选项
http://blog.csdn.net/u014328976/article/details/46745349 GCC编译器 gcc hello.c -o hello ...
- gcc编译器与基本类型3
C语言发展史 1969年贝尔实验室 肯尼斯·蓝·汤普逊,丹尼斯·李奇开发了B语言 ->Unix,New B语言,改名C语言83年提出C语言标准 1989年十二月正式通过C语言标准,C89标准 C ...
- 如何使用gcc编译器
开始... 首先,我们应该知道如何调用编译器.实际上,这很简单.我们将从那个著名的第一个C程序开始. #include <stdio.h> int main() { printf(&quo ...
随机推荐
- 裸辞闭关2个月,成功进大厂!吃透这份562页《算法知识手册》,化身offer收割机!
前言 记得我上本科的时候,我们老师一直跟我们强调:"算法才是编程的灵魂,一定要把算法学好."因为不管你是Java编程爱好者.还是python的忠实粉丝,亦或觉得PHP才是这个世界最 ...
- 基于ABP落地领域驱动设计-01.全景图
什么是领域驱动设计? 领域驱动设计(简称:DDD)是一种针对复杂需求的软件开发方法.将软件实现与不断发展的模型联系起来,专注于核心领域逻辑,而不是基础设施细节.DDD适用于复杂领域和大规模应用,而不是 ...
- StringUtils中的常量
//空格字符串 public static final String SPACE = " "; //空字符串 public static final String EMPTY = ...
- .Net RabbitMQ实战指南——服务日志
RabbitMQ的日出输入方式有很多种:file.console .syslog .exchange. 在RabbitMQ中,日志级别有none(0).critical(4).error(8).war ...
- 23、mysql高可用实践
23.1.mysql高可用业务需求: 23.2.mysql高可用架构图(单主热备模式): 23.6.部署drbd.heartbeat.mysql的主从同步: 1.部署heartbeat:参考" ...
- 关于TreeView的实例
前台代码 (只需要有TreeView控件, 添加ID,其他默认生成) <form id="form1" runat="server"> <di ...
- Html:id,name,class之间的有什么区别?
name 一个name可以同时对应多个控件,比如checkbox和radio,主要用于获取提交表单的某表单域信息, 作为可与服务器交互数据的HTML元素的服务器端的标示,比如input.select. ...
- Linux:linux服务器稳定性压力测试工具stress安装与使用
stress是一个linux下的压力测试工具,专门为那些想要测试自己的系统,完全高负荷和监督这些设备运行的用户. 1. stress1.0.4下载地址 下载:https://fossies.org/l ...
- 理解Python中的闭包
1.定义 闭包是函数式编程的一个重要的语法结构,函数式编程是一种编程范式 (而面向过程编程和面向对象编程也都是编程范式).在面向过程编程中,我们见到过函数(function):在面向对象编程中,我们见 ...
- C语言:缓冲区
缓冲区(Buffer)又称为缓存(Cache),是内存空间的一部分.也就是说,计算机在内存中预留了一定的存储空间,用来暂时保存输入或输出的数据,这部分预留的空间就叫做缓冲区(缓存).有时候,从键盘输入 ...