GCC后端及汇编发布(7)

3.3.2. 重组识别树

回到 main ,下来调用 process_tree 来识别这棵树。它将尝试简化这棵树,并把节点赋予用于输出的函数。

 

2582 static void                                                                                                 in genreocg.c

2583 process_tree (struct decision_head *head, enum routine_type subroutine_type)

2584 {

2585   if (head->first == NULL)

2586   {

2587     /* We can elide peephole2_insns, but not recog or split_insns.  */

2588     if (subroutine_type == PEEPHOLE2)

2589       return ;

2590   }

2591   else

2592   {

2593     factor_tests (head);

2594

2595     next_subroutine_number = 0;

2596     break_out_subroutines (head, 1);

2597     find_afterward (head, NULL);

2598

2599     /* We run this after find_afterward, because find_afterward needs

2600       the redundant DT_mode tests on predicates to determine whether

2601       two tests can both be true or not.  */

2602     simplify_tests (head);

2603

2604      write_subroutines (head, subroutine_type);

2605   }

2606

2607   write_subroutine (head, subroutine_type);

2608 }

 

注意到对于我们这里的例子,参数 head 指向 recog_trees ,而参数 subroutine_type RECOG 。显然,我们的 recog_trees 不是空的。那么调用 factor_tests 。它将比较相邻的兄弟节点,提取出它们中公共的测试部分,并这部分构建新的 decision 节点。

 

1481 static void

1482 factor_tests (struct decision_head *head)                                                      in genreocg.c

1483 {

1484   struct decision *first, *next;

1485

1486   for (first = head->first; first && first->next; first = next)

1487   {

1488     enum decision_type type;

1489     struct decision *new, *old_last;

1490

1491     type = first->tests->type;

1492     next = first->next;

1493

1494     /* Want at least two compatible sequential nodes.  */

1495     if (next->tests->type != type)

1496       continue ;

1497

1498     /* Don't want all node types, just those we can turn into

1499       switch statements.  */

1500     if (type != DT_mode

1501          && type != DT_code

1502          && type != DT_veclen

1503          && type != DT_elt_zero_int

1504          && type != DT_elt_one_int

1505          && type != DT_elt_zero_wide_safe)

1506       continue ;

1507

1508     /* If we'd been performing more than one test, create a new node

1509       below our first test.  */

1510     if (first->tests->next != NULL)

1511     {

1512       new = new_decision (first->position, &first->success);

1513       new->tests = first->tests->next;

1514       first->tests->next = NULL;

1515     }

1516

1517      /* Crop the node tree off after our first test.  */

1518     first->next = NULL;

1519     old_last = head->last;

1520     head->last = first;

1521

1522     /* For each compatible test, adjust to perform only one test in

1523       the top level node, then merge the node back into the tree.  */

1524     do

1525     {

1526       struct decision_head h;

1527

1528       if (next->tests->next != NULL)

1529       {

1530         new = new_decision (next->position, &next->success);

1531         new->tests = next->tests->next;

1532         next->tests->next = NULL;

1533       }

1534       new = next;

1535       next = next->next;

1536       new->next = NULL;

1537       h.first = h.last = new;

1538

1539       merge_trees (head, &h);

1540     }

1541     while (next && next->tests->type == type);

1542

1543     /* After we run out of compatible tests, graft the remaining nodes

1544       back onto the tree.  */

1545     if (next)

1546     {

1547       next->prev = head->last;

1548       head->last->next = next;

1549       head->last = old_last;

1550     }

1551   }

1552

1553   /* Recurse.  */

1554   for (first = head->first; first; first = first->next)

1555     factor_tests (&first->success);

1556 }

 

对于没有兄弟的 decision 节点,这个函数没有作用,直到我们来到下面的节点。

f18

18 factor_tree 函数,图 1

上面在 1486 行, head->first 指向感兴趣节点的 first 链中的节点,其第一个子节点是 DT_mode 类型。而在其 next 链中的节点也具有 DT_mode 类型的第一个子节点。 1495 1500 行的测试通过。因此类型 DT_mode tests 的子节点被提取入一个新的 decision 节点,在调用 merge_trees 之前,我们可以得到以下我们例子的树。注意到绿色的节点,从 recog_trees 出发,是不可到达的。不过,这些节点现在还是可以访问的,因为我们持有指向它们的指针。

f19

19 factor_tree 函数,图 2

注意到感兴趣的节点是 merge_trees 的第一个参数,而 new 节点是第二个参数。显然,在 1438 行,对所检查的节点 nodes_identical 返回 1 。而 merge_accept_insn ,对于这些节点则不做任何事。那么 merge_trees 再次如下图所示递归。

f20

20 merge_trees 函数,图 1

现在我们具有如下的调用栈:

merge_trees (from factor_tests )

   |-- à merge_trees (recurse)

        |-- à merge_trees (recurse)

对于感兴趣的节点, nodes_identical 返回 0 ,然后 maybe_both_true 也返回 0 ,因为两者的第一个 decision_test 节点都是 DT_code 类型, insert_before 保持为 null ,两个感兴趣的 decision 节点将被链接成兄弟,如下图所示。

f21

21 merge_trees 函数,图 2

随着最里层的 merge_trees 返回,在栈上方的 merge_trees 依次返回,最后回到 factor_test 。我们仍然在 factor_test 1486 1551 行的 FOR 循环中。看到在 1486 行, next 指向下图中所示的节点。

f22

22 merge_trees 函数,图 3

因为节点 next next 域是 null ,我们立即从这个 FOR 循环中跳出。然后我们在 factor_test 1554 1555 行继续处理余下的节点,如 21 所示。重复上面的步骤,最后我们可以得到下面的图。

f23

23 factor_tree 函数,图 3

3.3.2. 把节点输出为子例程

回到 process_tree break_out_subroutines 被调用来计算 HEAD 的子节点的数目。如果 initial 0 ,并且数目足够大,使得 HEAD 中的第一个节点,在所要产生 C 代码中,开始另一个函数。

 

1603 static int

1604 break_out_subroutines (struct decision_head *head, int initial)                       in genreocg.c

1605 {

1606   int size = 0;

1607   struct decision *sub;

1608

1609   for (sub = head->first; sub; sub = sub->next)

1610     size += 1 + break_out_subroutines (&sub->success, 0);

1611

1612   if (size > SUBROUTINE_THRESHOLD && ! initial)

1613   {

1614     head->first->subroutine_number = ++next_subroutine_number ;

1615     size = 1;

1616   }

1617   return size;

1618 }

 

出于演示的目的,对于我们的例子,假定上面的 SUBROUTINE_THRESHOLD 4 。那么我们可以得到如下的图形。注意图中 size subroutine_number 的值。

f24

24 process_tree 函数,图 1

接着是 find_afterward 。我们已经看到 factor_tests 将提取相邻兄弟节点的公共测试部分,而 find_afterward 将遍历所有的兄弟节点,并把匹配的节点链接在一起。对于来自 process_tree 的调用,其第二个参数 real_afterward null

 

1623 static void

1624 find_afterward (struct decision_head *head, struct decision *real_afterward)   in genreocg.c

1625 {

1626   struct decision *p, *q, *afterward;

1627

1628   /* We can't propagate alternatives across subroutine boundaries.

1629     This is not incorrect, merely a minor optimization loss.  */

1630

1631   p = head->first;

1632   afterward = (p->subroutine_number > 0 ? NULL : real_afterward);

1633

1634   for ( ; p ; p = p->next)

1635   {

1636     /* Find the next node that might be true if this one fails.  */

1637     for (q = p->next; q ; q = q->next)

1638       if (maybe_both_true (p, q, 1))

1639         break ;

1640

1641     /* If we reached the end of the list without finding one,

1642       use the incoming afterward position.  */

1643     if (!q)

1644       q = afterward;

1645     p->afterward = q;

1646     if (q)

1647       q->need_label = 1;

1648   }

1649

1650   /* Recurse.  */

1651   for (p = head->first; p ; p = p->next)

1652     if (p->success.first)

1653       find_afterward (&p->success, p->afterward);

1654

1655   /* When we are generating a subroutine, record the real afterward

1656     position in the first node where write_tree can find it, and we

1657     can do the right thing at the subroutine call site.  */

1658   p = head->first;

1659   if (p->subroutine_number > 0)

1660     p->afterward = real_afterward;

1661 }

 

对于没有兄弟的 decision 节点, find_afterward 只是把其 afterward 填成 null 。我们使用上面产生的树作为例子,当来到下面的节点时,我们看到以下的图。

f26

25 process_tree 函数,图 2

对于这两个节点, maybe_both_true 1638 行返回 0 。该函数的目的是找出可能同时为 true 的兄弟节点。作为结果,所有我们例子中的节点都具有为 null afterward 。在提取公共部分之后, simplify_tests 被调用来简化任一节点上的测试。

 

1566 static void

1567 simplify_tests (struct decision_head *head)                                                  in genreocg.c

1568 {

1569   struct decision *tree;

1570

1571   for (tree = head->first; tree; tree = tree->next)

1572   {

1573     struct decision_test *a, *b;

1574

1575     a = tree->tests;

1576     b = a->next;

1577     if (b == NULL)

1578       continue ;

1579

1580     /* Find a predicate node.  */

1581     while (b && b->type != DT_pred)

1582       b = b->next;

1583     if (b)

1584     {

1585       /* Due to how these tests are constructed, we don't even need

1586         to check that the mode and code are compatible -- they were

1587         generated from the predicate in the first place.  */

1588       while (a->type == DT_mode || a->type == DT_code)

1589         a = a->next;

1590       tree->tests = a;

1591     }

1592   }

1593

1594   /* Recurse.  */

1595   for (tree = head->first; tree; tree = tree->next)

1596     simplify_tests (&tree->success);

1597 }

 

这个函数的代码相当简单。它移除断言中重复的 mode 测试或 code 测试。之后,我们可以得到以下的树。

f26

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值