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.
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.
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.
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.
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.
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.
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.
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.
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.
figure 26 : function of process_tree, figure 3