【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 ...
随机推荐
- CSS 奇思妙想 | 全兼容的毛玻璃效果
通过本文,你能了解到 最基本的使用 CSS backdrop-filter 实现磨砂玻璃(毛玻璃)的效果 在至今不兼容 backdrop-filter 的 firefox 浏览器,如何利用一些技巧性的 ...
- jQuery获取标签信息
<!DOCTYPE html><html><head> <meta charset="utf-8"/> <titl ...
- excel匹配函数vlookup和lookup
1.vlookup(查找的条件,查找的区域,满足查找条件后需要返回的值在选中的查找区域的第几列,精确匹配还是近似匹配(精确匹配为0或False表示,反之为1或True)) =VLOOKUP(J2,$G ...
- Kubernetes使用节点亲缘性将POD调度到特定节点上
节点污点可以用来让pod远离特定的节点,尽量在不修改已有pod信息的前提,通过在节点添加污点信息,来拒绝pod在某些节点上的部署. 而现在介绍一种叫做节点亲缘性,通过明确的在pod中添加的信息,来决定 ...
- 乘风破浪,Windows11设计和开发指导,全新图标字体和云母材质
Windows11全新的布局设计 Windows 11全新的布局设计已设计为支持现代应用体验.渐进的圆角.嵌套元素和一致的排水沟相结合,营造出柔和.平静.平易近人的效果,强调目的的统一和易用性. ht ...
- P2P技术(2)——NAT穿透
P2P可以是一种通信模式.一种逻辑网络模型.一种技术.甚至一种理念.在P2P网络中,所有通信节点的地位都是对等的,每个节点都扮演着客户机和服务器双重角色,节点之间通过直接通信实现文件信息.处理器运算能 ...
- AvtiveMQ与SpringBoot结合
首先来了解下ActivieMQ的应用场景,消息队列中间件是分布式系统中重要的组件,主要解决应用耦合,异步消息,流量削锋等问题.实现高性能,高可用,可伸缩和最终一致性架构是大型分布式系统不可缺少的中间件 ...
- Linux | Linux常用指令学习笔记
@ 目录 前言 1. Linux目录结构: 2. 运行级别: init.systemctl 3. vim相关快捷键: 4. 开关机相关命令: shutdowm.halt.reboot.sync.log ...
- Docker:Docker常用命令
docker信息 ##查看docker容器版本 docker version ##查看docker容器信息 docker info ##查看docker容器帮助 docker --help 镜像列表 ...
- linux学习之路第五天(文件目录类第一部分)
文件目录类 pwd 指令 基本语法 pwd (显示当前目录的绝对路径) Ls 指令 cd 指令 -代表的是上一级目录 mkdir指令 用于创建目录 基本语法 mkdir [选项] 要创建的目录 常用选 ...