中间表示- 控制流图

基本概念

基本块:是语句的一个序列,从第一条执行到最后一条

  • 不能从中间进入,不能从中间退出,即跳转指令只能出现在最后

控制流图:控制流图是一个有向图G=(V,E)

  • 节点V:是基本块
  • 边E:是基本块之间的跳转关系

中间表示- 控制流图_第1张图片

控制流图的定义

是更精细的三地址码

中间表示- 控制流图_第2张图片

 数据结构定义(以B为例)

struct Block {
    Label_t label;
    List_t stms;
    Jump_t j;
};

如何生成控制流图?

(1)可以直接从抽象语法树生成

  • 如果高层语言具有特别规整的控制流结构的话较容易

(2)也可以先生成三地址码,然后继续生成控制流图

  • 对于像C这样的语言更合适,因为其中包含像goto这样的非结构化的控制流语句
  • 更加通用(阶段划分!)

使用控制流图的编译器结构

中间表示- 控制流图_第3张图片

由三地址码生成控制流图算法(线性扫描算法)

List_t stms;            // 三地址码中所有语句
List_t blocks = {};     // 控制流图中的所有基本块
Block_t b = Block_fresh();  // 一个初始的空的基本块
scan_stms()
{
    foreach(s ∈ stms)
        if (s is "Label L")     // s是标号
            b.label = L;
        else (s is some jump)   // s是跳转
            b.j = s;
            blocks ∪= {b};
            b = Block_fresh();
        else                    // s是普通指令
            b.stms ∪= {s};
}

控制流图的基本操作

● 标准的图论算法都可以用在控制流图的操作上

  • 各种遍历算法、生成树、必经节点结构等等。

● 图节点的顺序有重要的应用

  • 拓扑序、逆拓扑序、近似拓扑序等等。

这里我们不详细展开这些算法,而是通过研究一个具体的例子来展示基本图算法的应用

  • 死基本块删除优化

例子:死基本块删除优化

int f()
{
    int i = 3;
    while (i < 10)
    {
        i = i + 1;
        printi(i);
        continue;
        printi(i);
    }
    return 0;
}

对上述程序,构建出对应的控制流图如下(L0为入口块,L2为出口块)

中间表示- 控制流图_第4张图片

通过观察我们可以看出,上图中并没有任何一条边进入L3(即L3的入度为0),L3这个块是从L0出发对这个图做遍历不可达的一个块,这样的块称为死基本块。这个块是不可能被执行到的。

死基本块删除算法

  • 输入:控制流图g
  • 输出:经过死基本块删除后的控制流图
dead_blocks_elim(g)
    dfs(g);
    for (each node in g)
        if (!visited(n))
            delete(n);

你可能感兴趣的:(编译原理,数据结构,编译原理,c语言,开发语言)