GCC-3.4.6源代码学习笔记(176)

5.13.5.3.2.2.1.          按调用次序排序

为了下面处理的方便起见,在 1253 行,把所有的 cgraph_node 按对应函数调用的次序排序,把有向图转化为队列(其满足拓扑排序( topological order )的定义)。

 

548  static int

549  cgraph_postorder (struct cgraph_node **order)                                           in cgraphunit.c

550  {

551    struct cgraph_node *node, *node2;

552    int stack_size = 0;

553    int order_pos = 0;

554    struct cgraph_edge *edge, last;

555 

556    struct cgraph_node **stack =

557      xcalloc (cgraph_n_nodes , sizeof (struct cgraph_node *));

558 

559    /* We have to deal with cycles nicely, so use a depth first traversal

560      output algorithm. Ignore the fact that some functions won't need

561      to be output and put them into order as well, so we get dependencies

562      right through intline functions.  */

563    for (node = cgraph_nodes ; node; node = node->next)

564      node->aux = NULL;

565    for (node = cgraph_nodes ; node; node = node->next)

566      if (!node->aux)

567      {

568        node2 = node;

569        if (!node->callers)

570           node->aux = &last;

571        else

572           node->aux = node->callers;

573        while (node2)

574         {

575           while (node2->aux != &last)

576           {

577            edge = node2->aux;

578             if (edge->next_caller)

579               node2->aux = edge->next_caller;

580            else

581               node2->aux = &last;

582            if (!edge->caller->aux)

583             {

584               if (!edge->caller->callers)

585                 edge->caller->aux = &last;

586               else

587                 edge->caller->aux = edge->caller->callers;

588               stack[stack_size++] = node2;

589               node2 = edge->caller;

590               break ;

591             }

592           }

593           if (node2->aux == &last)

594           {

595            order[order_pos++] = node2;

596            if (stack_size)

597               node2 = stack[--stack_size];

598            else

599               node2 = NULL;

600           }

601         }

602      }

603    free (stack);

604    return order_pos;

605  }

 

这里使用的算法是 Kahn 1962 年提出的,具体的算法如下:

L ← Empty list that will contain the sorted elements
S ← Set of all nodes with no incoming edges
while

 S is non-empty do

    
remove a node n from S
    
insert n into L
    
for each
 node m with an edge e
 from n to m do

       
 
remove edge e from the graph
        
if
 m has no other incoming edges then

            
insert m into S
if

 graph has edges then

    
output error message (graph has at least one cycle)
else

 
    
output message (proposed topologically sorted order: L)

不过在这里的实现中,环( cycle )不是问题(由直接或间接递归产生),因为 C++ 程序总是从 main 函数开始的,出现环时,以离 main 函数最远的函数作为起点。毫无疑问,递归的函数是不能内联的,否则会导致无限展开。不过这里我们暂时不管它。

以下面的函数调用关系为例,我们已经知道 cgraph_node 节点是在函数第一次被调用时构建的,那么它们在 cgraph_nodes 中的次序就反映了调用时间的先后。在下图中,函数的调用时间次序是: 0 -> 1-> 2-> 3-> 1

t1

 

119 :对节点 0 的处理

因为函数 0 没有调用者,很清晰地,它就是排序后的第一个节点。

t2

 

120 :对节点 1 的处理

函数 1 出现在一个递归环里,那么其节点的 AUX 追踪到下一个调用者的 cgraph_edge

t3

121 :对节点 1 的第二次处理

重复处理函数 1 ,把它缓存入 stack ,进入其下一个调用者。

t4

122 :对节点 3 的处理

继续深入函数 1 的调用链,函数 3 尚不是最终调用者,亦把它缓存入 stack

t5

123 :对节点 2 的处理

函数 2 在对函数 1 调用链的最开头,而且它亦为函数 1 所调用,不过函数 1 已被处理,接受它成为排序后节点。

t6

124 :对 stack 中节点的处理

Stack 中的节点接着以后进先出的次序取出并进入排序队列。排序后的次序是: 0-> 2 -> 3 -> 1

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值