GCC's bacl-end & assemble emission (7)

3.3.2. Reorgnize Recongnition Tree

Back to main , next process_tree is invoked to reorgnize the tree. It will try to simplify the tree and assign nodes to subroutines for output.

 

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 }

 

Notice that for our example here, the parameter head points to recog_trees , and the parameter subroutine_type is RECOG. Obviously, our recog_trees is not empty. Then factor_tests is invoked. It will compare adjacent sibling nodes, factor out the common tests among them, and from which create new decision node.

 

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 }

 

For decision nodes without sibling, this function has no effect, till we arrive following nodes.

f18

 

figure 18  : function of factor_tree, figure 1

At line 1486 above, head->first points to the nodes in the first chain of the interested node whose first tests sub-nodes is of type DT_mode. And node in its next chain also has first sub-node of type DT_mode. Test of line 1495 and 1500 pass. So sub-nodes of tests of type DT_mode is factored out into a new decision node, before invoking merge_trees we can get following tree for our example. Notice that nodes in green are unreachable when departing from recog_trees now. However, they are still accessible now, as we have kept a pointer to them.

f19

figure 19  : function of factor_tree, figure 2

Notice that the node in interested is the first parameter and the new node is the second parameter of merge_trees . Obviously, at line 1438, nodes_identical returns 1 for nodes under check. And merge_accept_insn does nothing for these nodes. And merge_trees is recursed again indicated by following diagram.

f20

figure 20  : function of merge_trees, figure 1

Now we have following call stack:

merge_trees (from factor_tests )

   |-- à merge_trees (recurse)

        |-- à merge_trees (recurse)

For nodes in interested, nodes_identical returns 0, then maybe_both_true returns 0 too, as both first decision_test nodes are of type DT_code, insert_before keeps null, two decision nodes in interested will be linked as sibling indicated in following diagram.

f21

figure 21  : function of merge_trees, figure 2

With the most inner merge_trees returns, merge_trees above in the stack returns in turn and back to factor_test . We are still inside the FOR loop from line 1486 to 1551 in factor_test . Just see that next at line 1486 points to the node in following figure.

f22

figure 22  : function of merge_trees, figure 3

As the next field of the next node is null, we jump out the FOR loop immediately. Then we continue handle the rest nodes with factor_test in line 1554, 1555, which is same as figure 21 . Repeating the step above, we can finally get following diagram.

f23

 

figure 23  : function of factor_tree, figure 3

3.3.2. Assign Nodes into Subroutines

Back to process_tree , break_out_subroutines is invoked to count the number of subnodes of HEAD. If initial is zero, and the number is high enough, make the first node in HEAD start a separate subroutine in the C code that is generated.

 

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 }

 

For purpose of illustration, for our example, assume above SUBROUTINE_THRESHOLD is 4. Then we can get following figure. Pay attention to the value of size and subroutine_number in the figure.

f24

figure 24  : function of process_tree, figure 1

Next comes find_afterward . We have seen that factor_tests will factor out common tests part of adjacent sibling nodes, while find_afterward will visit all sibling nodes and link those matched tegother. For its invocation from process_tree , the second parameter real_afterward is 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 }

 

For decision nodes without sibling, find_afterward just fill it’s afterward with null. We use the tree generated above as an example, we just see following figure when arriving following nodes.

f25

figure 25  : function of process_tree, figure 2

maybe_both_true at line 1638 returns 0 for these nodes. The purpose of the function is to find out sibling nodes that maybe true simultaneous. As result, all nodes in our example have afterward of null. After factoring, simplify_tests is invoked to try to simplify the tests on any one node.

 

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 }

 

The code of the function is quite simple. It removes mode tests or code tests that are redundant with predicates. After it, we can get following tree.

f26

figure 26  : function of process_tree, figure 3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值