#ifndef FIRST_PSEUDO_REGISTER #define NULL 0 #include "config.h" #include "rtl.h" #include "tree.h" #include "insn-flags.h" #endif /* Functions and data structures for expanding case statements. */ /* Case label structure, used to hold info on labels within case statements. We handle "range" labels; for a single-value label as in C, the high and low limits are the same. */ struct case_node { struct case_node *left; struct case_node *right; struct case_node *parent; tree low; tree high; tree test_label; tree code_label; }; typedef struct case_node case_node; typedef struct case_node *case_node_ptr; void balance_case_nodes (); void emit_case_nodes (); void group_case_nodes (); void emit_jump_if_reachable (); /* Generate code to jump to LABEL if OP1 and OP2 are equal. */ static void do_jump_if_equal (op1, op2, label, unsignedp) rtx op1, op2, label; int unsignedp; { if (GET_CODE (op1) == CONST_INT && GET_CODE (op2) == CONST_INT) { if (INTVAL (op1) == INTVAL (op2)) emit_jump (label); } else { emit_cmp_insn (op1, op2, 0, unsignedp, 0); emit_jump_insn (gen_beq (label)); } } /* Not all case values are encountered equally. This function uses a heuristic to weight case labels, in cases where that looks like a reasonable thing to do. Right now, all we try to guess is text, and we establish the following weights: chars above space: 16 digits: 16 default: 12 space, punct: 8 tab: 4 newline: 2 other "\" chars: 1 remaining chars: 0 Under this weighting, ranges are automagically taken care of. */ #include static char *cost_table; static int use_cost_table; void estimate_case_costs (node, default_label) case_node_ptr node; rtx default_label; { tree min_ascii = build_int_2 (-1, -1); tree max_ascii = convert (TREE_TYPE (node->high), build_int_2 (127, 0)); case_node_ptr n; use_cost_table = 0; /* If the user is running without default, who are we to guess where values are likely to land? */ if (default_label == 0) return; /* See if all the case expressions look like text. It is text if the lowest constant is >= -1 and the highest constant is <= 127. If the case expression is unsigned, suppress the test for >= -1, since it would always be true. */ for (n = node; n; n = n->right) if ((! TREE_UNSIGNED (TREE_TYPE (n->low)) && tree_int_cst_lt (n->low, min_ascii)) || tree_int_cst_lt (max_ascii, n->high)) return; /* All interesting values with within the range of interesting ASCII characters. */ if (cost_table == NULL) { int i; cost_table = ((char *)malloc (129)) + 1; bzero (cost_table-1, 128); for (i = 0; i < 128; i++) { if (isalnum (i)) cost_table[i] = 16; else if (ispunct (i)) cost_table[i] = 8; else if (iscntrl (i)) cost_table[i] = -1; } cost_table[' '] = 8; cost_table['\t'] = 4; cost_table['\0'] = 4; cost_table['\n'] = 2; cost_table['\f'] = 1; cost_table['\v'] = 1; cost_table['\b'] = 1; } use_cost_table = 1; } /* Scan an ordered list of case nodes combining those with consecutive values or ranges. Eg. three separate entries 1: 2: 3: become one entry 1..3: */ void group_case_nodes (head) case_node_ptr head; { case_node_ptr node = head; while (node) { rtx lb = next_real_insn (label_rtx (node->code_label)); case_node_ptr np = node; /* Try to group the successors of NODE with NODE. */ while (((np = np->right) != 0) /* Do they jump to the same place? */ && next_real_insn (label_rtx (np->code_label)) == lb /* Are their ranges consecutive? */ && tree_int_cst_equal (np->low, combine (PLUS_EXPR, node->high, integer_one_node))) { node->high = np->high; } /* NP is the first node after NODE which can't be grouped with it. Delete the nodes in between, and move on to that node. */ node->right = np; node = np; } } /* Take an ordered list of case nodes and transform them into a near optimal binary tree, on the assumtion that any target code selection value is as likely as any other. The transformation is performed by splitting the ordered list into two equal sections plus a pivot. The parts are then attached to the pivot as left and right branches. Each branch is is then transformed recursively. */ void balance_case_nodes (head, parent) case_node_ptr *head; case_node_ptr parent; { register case_node_ptr np; np = *head; if (np) { int cost = 0; int i = 0; int ranges = 0; register case_node_ptr *npp; case_node_ptr left; /* Count the number of entries on branch. Also count the ranges. */ while (np) { if (!tree_int_cst_equal (np->low, np->high)) { ranges++; if (use_cost_table) { int hi_cost = cost_table[TREE_INT_CST_LOW (np->high)]; if (hi_cost < 0) use_cost_table = 0; else cost += hi_cost; } } if (use_cost_table) { int lo_cost = cost_table[TREE_INT_CST_LOW (np->low)]; if (lo_cost < 0) use_cost_table = 0; else cost += lo_cost; } else cost += 1; i++; np = np->right; } if (i > 2) { /* Split this list if it is long enough for that to help. */ npp = head; left = *npp; if (use_cost_table) { /* Find the place in the list that bisects the list's total cost, Here I gets half the total cost. */ int n_moved = 0; i = (cost + 1) / 2; while (1) { /* Skip nodes while their cost does not reach that amount. */ if (!tree_int_cst_equal ((*npp)->low, (*npp)->high)) i -= cost_table[TREE_INT_CST_LOW ((*npp)->high)]; i -= cost_table[TREE_INT_CST_LOW ((*npp)->low)]; if (i <= 0) break; npp = &(*npp)->right; n_moved += 1; } if (n_moved == 0) { /* Leave this branch lopsided, but optimize left-hand side and fill in `parent' fields for right-hand side. */ np = *head; np->parent = parent; balance_case_nodes (&np->left, np); for (; np->right; np = np->right) np->right->parent = np; return; } } /* If there are just three nodes, split at the middle one. */ else if (i == 3) npp = &(*npp)->right; else { /* Find the place in the list that bisects the list's total cost, where ranges count as 2. Here I gets half the total cost. */ i = (i + ranges + 1) / 2; while (1) { /* Skip nodes while their cost does not reach that amount. */ if (!tree_int_cst_equal ((*npp)->low, (*npp)->high)) i--; i--; if (i <= 0) break; npp = &(*npp)->right; } } *head = np = *npp; *npp = 0; np->parent = parent; np->left = left; /* Optimize each of the two split parts. */ balance_case_nodes (&np->left, np); balance_case_nodes (&np->right, np); } else { /* Else leave this branch as one level, but fill in `parent' fields. */ np = *head; np->parent = parent; for (; np->right; np = np->right) np->right->parent = np; } } } /* Search the parent sections of the case node tree to see if a test for the lower bound of NODE would be redundant. The instructions to synthesis the case decision tree are output in the same order as nodes are processed so it is known that if a parent node checks the range of the current node minus one that the current node is bounded at its lower span. Thus the test would be redundant. */ static int node_has_low_bound (node) case_node_ptr node; { tree low_minus_one; case_node_ptr pnode; if (node->left) { low_minus_one = combine (MINUS_EXPR, node->low, integer_one_node); /* Avoid the screw case of overflow where low_minus_one is > low. */ if (tree_int_cst_lt (low_minus_one, node->low)) for (pnode = node->parent; pnode; pnode = pnode->parent) { if (tree_int_cst_equal (low_minus_one, pnode->high)) return 1; /* If a parent node has a left branch we know that none of its parents can have a high bound of our target minus one so we abort the search. */ if (node->left) break; } } return 0; } /* Search the parent sections of the case node tree to see if a test for the upper bound of NODE would be redundant. The instructions to synthesis the case decision tree are output in the same order as nodes are processed so it is known that if a parent node checks the range of the current node plus one that the current node is bounded at its upper span. Thus the test would be redundant. */ static int node_has_high_bound (node) case_node_ptr node; { tree high_plus_one; case_node_ptr pnode; if (node->right == 0) { high_plus_one = combine (PLUS_EXPR, node->high, integer_one_node); /* Avoid the screw case of overflow where high_plus_one is > high. */ if (tree_int_cst_lt (node->high, high_plus_one)) for (pnode = node->parent; pnode; pnode = pnode->parent) { if (tree_int_cst_equal (high_plus_one, pnode->low)) return 1; /* If a parent node has a right branch we know that none of its parents can have a low bound of our target plus one so we abort the search. */ if (node->right) break; } } return 0; } /* Search the parent sections of the case node tree to see if both tests for the upper and lower bounds of NODE would be redundant. */ static int node_is_bounded (node) case_node_ptr node; { if (node->left || node->right) return 0; return node_has_low_bound (node) && node_has_high_bound (node); } /* Emit an unconditional jump to LABEL unless it would be dead code. */ void emit_jump_if_reachable (label) rtx label; { rtx last_insn; if (GET_CODE (get_last_insn ()) != BARRIER) emit_jump (label); } /* Emit step-by-step code to select a case for the value of INDEX. The thus generated decision tree follows the form of the case-node binary tree NODE, whose nodes represent test conditions. UNSIGNEDP is nonzero if we should do unsigned comparisons. Care is taken to prune redundant tests from the decision tree by detecting any boundary conditions already checked by emitted rtx. (See node_has_high_bound, node_has_low_bound and node_is_bounded, above.) Where the test conditions can be shown to be redundant we emit an unconditional jump to the target code. As a further optimization, the subordinates of a tree node are examined to check for bounded nodes. In this case conditional and/or unconditional jumps as a result of the boundary check for the current node are arranged to target the subordinates associated code for out of bound conditions on the current node node. */ void emit_case_nodes (index, node, default_label, unsignedp) rtx index; case_node_ptr node; rtx default_label; int unsignedp; { /* If INDEX has an unsigned type, we must make unsigned branches. */ typedef rtx rtx_function (); rtx_function *gen_bgt_pat = unsignedp ? gen_bgtu : gen_bgt; rtx_function *gen_bge_pat = unsignedp ? gen_bgeu : gen_bge; rtx_function *gen_blt_pat = unsignedp ? gen_bltu : gen_blt; rtx_function *gen_ble_pat = unsignedp ? gen_bleu : gen_ble; int defaulted_left = 0; int defaulted_right = 0; if (node->test_label) { /* If this test node requires a label it follows that it must be preceeded by an unconditional branch. If control can pass to this point we can assume that a "br default" is in order. */ emit_jump_if_reachable (default_label); expand_label (node->test_label); } if (tree_int_cst_equal (node->low, node->high)) { /* Node is single valued. */ do_jump_if_equal (index, expand_expr (node->low, 0, VOIDmode, 0), label_rtx (node->code_label), unsignedp); if (node->right) { if (node->left) { /* This node has children on either side. */ emit_cmp_insn (index, expand_expr (node->high, 0, VOIDmode, 0), 0, unsignedp, 0); if (node_is_bounded (node->right)) { emit_jump_insn ((*gen_bgt_pat) (label_rtx (node->right->code_label))); if (node_is_bounded (node->left)) emit_jump (label_rtx (node->left->code_label)); else emit_case_nodes (index, node->left, default_label, unsignedp); } else { if (node_is_bounded (node->left)) emit_jump_insn ((*gen_blt_pat) (label_rtx (node->left->code_label))); else { node->right->test_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); emit_jump_insn ((*gen_bgt_pat) (label_rtx (node->right->test_label))); emit_case_nodes (index, node->left, default_label, unsignedp); } emit_case_nodes (index, node->right, default_label, unsignedp); } } else { /* Here we have a right child but no left so we issue conditional branch to default and process the right child. */ /* Omit the conditional branch to default if we it avoid only one right child; it costs too much space to save so little time. */ if (node->right->right && !node_has_low_bound (node)) { emit_cmp_insn (index, expand_expr (node->high, 0, VOIDmode, 0), 0, unsignedp, 0); emit_jump_insn ((*gen_blt_pat) (default_label)); } if (node_is_bounded (node->right)) emit_jump (label_rtx (node->right->code_label)); else emit_case_nodes (index, node->right, default_label, unsignedp); } } else if (node->left) { if (use_cost_table && ! defaulted_right && cost_table[TREE_INT_CST_LOW (node->high)] < 12) { /* If our "most probably entry" is less probable than the default label, emit a jump to the default label using condition codes already lying around. With no right branch, a branch-greater-than will get us to the default label correctly. */ emit_cmp_insn (index, expand_expr (node->high, 0, VOIDmode, 0), 0, unsignedp, 0); emit_jump_insn ((*gen_bgt_pat) (default_label)); /* No sense doing this too often. */ defaulted_right = 1; } if (node_is_bounded (node->left)) emit_jump (label_rtx (node->left->code_label)); else emit_case_nodes (index, node->left, default_label, unsignedp); } } else { /* Node is a range. */ if (node->right) { if (node->left) { emit_cmp_insn (index, expand_expr (node->high, 0, VOIDmode, 0), 0, unsignedp, 0); if (node_is_bounded (node->right)) { /* Right hand node is fully bounded so we can eliminate any testing and branch directly to the target code. */ emit_jump_insn ((*gen_bgt_pat) (label_rtx (node->right->code_label))); } else { /* Right hand node requires testing so create a label to put on the cmp code. */ node->right->test_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); emit_jump_insn ((*gen_bgt_pat) (label_rtx (node->right->test_label))); } emit_cmp_insn (index, expand_expr (node->low, 0, VOIDmode, 0), 0, unsignedp, 0); emit_jump_insn ((*gen_bge_pat) (label_rtx (node->code_label))); if (node_is_bounded (node->left)) { /* Left hand node is fully bounded so we can eliminate any testing and branch directly to the target code. */ emit_jump (label_rtx (node->left->code_label)); } else emit_case_nodes (index, node->left, default_label, unsignedp); /* If right node has been given a test label above we must process it now. */ if (node->right->test_label) emit_case_nodes (index, node->right, default_label, unsignedp); } else { if (!node_has_low_bound (node)) { emit_cmp_insn (index, expand_expr (node->low, 0, VOIDmode, 0), 0, unsignedp, 0); emit_jump_insn ((*gen_blt_pat) (default_label)); } emit_cmp_insn (index, expand_expr (node->high, 0, VOIDmode, 0), 0, unsignedp, 0); emit_jump_insn ((*gen_ble_pat) (label_rtx (node->code_label))); if (node_is_bounded (node->right)) { /* Right hand node is fully bounded so we can eliminate any testing and branch directly to the target code. */ emit_jump (label_rtx (node->right->code_label)); } else emit_case_nodes (index, node->right, default_label, unsignedp); } } else if (node->left) { if (!node_has_high_bound (node)) { emit_cmp_insn (index, expand_expr (node->high, 0, VOIDmode, 0), 0, unsignedp, 0); emit_jump_insn ((*gen_bgt_pat) (default_label)); } emit_cmp_insn (index, expand_expr (node->low, 0, VOIDmode, 0), 0, unsignedp, 0); emit_jump_insn ((*gen_bge_pat) (label_rtx (node->code_label))); if (node_is_bounded (node->left)) { /* Left hand node is fully bounded so we can eliminate any testing and branch directly to the target code. */ emit_jump (label_rtx (node->left->code_label)); } else emit_case_nodes (index, node->left, default_label, unsignedp); } else { /* Node has no children so we check low and high bounds to remove redundant tests. In practice only one of the limits may be bounded or the parent node will have emmited a jump to our target code. */ if (!node_has_high_bound (node)) { emit_cmp_insn (index, expand_expr (node->high, 0, VOIDmode, 0), 0, unsignedp, 0); emit_jump_insn ((*gen_bgt_pat) (default_label)); } if (!node_has_low_bound (node)) { emit_cmp_insn (index, expand_expr (node->low, 0, VOIDmode, 0), 0, unsignedp, 0); emit_jump_insn ((*gen_bge_pat) (label_rtx (node->code_label))); } /* We allow the default case to drop through since it will picked up by calls to `jump_if_reachable' either on the next test label or at the end of the decision tree emission. */ } } }