Next: Profile information, Previous: Basic Blocks, Up: Control Flow
边表示从某个基本块A的结束到另一个基本块B的开头的可能的控制流转换。
我们称A是B的前驱,B是A的后继。在GCC中,边由edge
数据类型表示。
每个edge
作为两个基本块之间的链接:
一个edge
的src
成员指向前驱dest
基本块。
数据类型basic_block
的成员preds
和succs
,
指向块的前驱和后继们的边的type-safe向量。
当在一个边向量中访问边时,应该使用边迭代器。
边迭代器由edge_iterator
数据结构和一些可以使用的操作方法构成:
ei_start
edge_iterator
。
ei_last
edge_iterator
。
ei_end_p
edge_iterator
表示边向量中的最后一个边,则该断言为true
。
ei_one_before_end_p
edge_iterator
表示边向量中的倒数第二个边,则该断言为true
。
ei_next
edge_iterator
的指针,并使其指向序列中的下一个边。
ei_prev
edge_iterator
的指针,并使其指向序列中的上一个边。
ei_edge
edge_iterator
当前指向的edge
。
ei_safe_safe
edge_iterator
当前指向的edge
,
但是如果迭代器指向序列的结尾时,则返回NULL
。
该函数是为现有的代码提供的,即代码假设用NULL
边来表示序列的结尾。
宏FOR_EACH_EDGE
可以方便的用来访问前驱边或后继边序列。
当在遍历中会移除元素时,不要使用该宏,否则会错过这些元素。
这里有一个如何使用该宏的例子:
edge e; edge_iterator ei; FOR_EACH_EDGE (e, ei, bb->succs) { if (e->flags & EDGE_FALLTHRU) break; }
有许多原因会导致控制流从一个块传递到另一个。
一种可能是某条指令,例如CODE_LABEL
,在一个线形的指令流中,
总是起始一个新基本块。在这种情况下,
一个fall-thru边将基本块与随后的第一个比本块相连。
但是有许多其它原因会导致边被创建。
edge
的数据类型的flags
域用于存储我们处理的边的类型信息。
每个边都具有下列类型之一:
EDGE_FALLTHRU
。不像其它类型的边,
这些边必须直接进入基本块的指令流中。
函数force_nonfallthru
可以用于在需要重定向时插入一个无条件跳转。
注意这可能需要创建一个新基本块。
EDGE_ABNORMAL
和EDGE_EH
标识。
当更新指令流时,能够容易的将可能trapping的指令转换成non-traaping,
通过简单的将异常边移除。相反的转换比较困难,但是是不会发生的。
可以通过调用purge_dead_edges
来消除边。
在RTL表示中,异常边的目的地由附加在insn上的注解REG_EH_REGION
来指定。
在trapping调用的情况下,还设置了EDGE_ABNORMAL_CALL
标识。
在tree
表示中,该额外的标识没有被设置。
在RTL表示中,断言may_trap_p
可以用来检测指令是否还可能trap。
对于tree表示,可以用tree_could_trap_p
,
不过该断言只检测可能的内存trap,像在废除一个无效的指针地址。
EDGE_SIBCALL
和EDGE_ABNORMAL
在这种情况下被设置。
这些边只存在于RTL表示中。
EDGE_ABNORMAL
标识。
用来表示计算跳转的边通常会造成编译时间性能问题,
因为函数有许多标号组成,许多计算跳转可能具有密集的流图,
所以这些边需要特别仔细的处理。在编译过程的早期阶段,
GCC尝试避免这样的密集流图,通过因子化计算跳转。
例如,给定下列跳转,
goto *x; [ ... ] goto *x; [ ... ] goto *x; [ ... ]
将计算跳转提取公因子,会产生具有比较简单流图的代码序列:
goto y; [ ... ] goto y; [ ... ] goto y; [ ... ] y: goto *x;
但是,这种转换的典型问题是产生的结果代码具有运行时代价:
一个额外的跳转。因此计算跳转在编译器之后的过程里被un-factored。
当你工作于这些过程上时,需要注意。曾有许多已存的例子,
即对未公因子化的计算跳转编译时造成的头痛之事。
goto
到一个通过参数传给被调用者的标号的方式来返回到调用者那里。
传给嵌套函数的标号包含了特定的代码用来在函数调用之后进行清理工作。
这段代码被称为“nonlocal goto receivers”。
如果一个函数包含这样的非局部goto接受者,一个从调用到标号的边被创建,
并设置了EDGE_ABNORMAL
和EDGE_ABNORMAL_CALL
标识。
ENTRY_BLOCK_PTR
到基本块0。
目前,对备用入口点没有tree
表示。在RTL里,
备用入口点通过定义了LABEL_ALTERNATE_NAME
的CODE_LABEL
指定。
这能够被后端用于为通过不同上下文调用函数而生成备用prologues。
将来,Fortran90定义的多入口函数的完全支持需要被实现。