From: "Rahul Kharche" <rahul@IceraSemi.com>
To: "Paulo J. Matos" <pocmatos@gmail.com>
Cc: <gcc@gcc.gnu.org>, "sdkteam-gnu" <sdkteam-gnu@IceraSemi.com>
Subject: RE: Clustering switch cases
Date: Tue, 31 Aug 2010 15:59:00 -0000 [thread overview]
Message-ID: <4D60B0700D1DB54A8C0C6E9BE6916370106C745A@EXCHANGEVS.IceraSemi.local> (raw)
In-Reply-To: <AANLkTim=OiepFQ+-vqw1kJ_7zr+s9Sau1fBhoazABEWy@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 320 bytes --]
> I will be looking at the patch Rahul posted and will try to see if I
> can improve on it.
See attached patch (again) that Paulo is referring to. Sending to GCC
failed due to email client issues.
I have another patch for http://gcc.gnu.org/ml/gcc/2010-08/msg00413.html
Which I will send out shortly.
Rahul
[-- Attachment #2: switch_case_clusters.patch --]
[-- Type: application/octet-stream, Size: 29885 bytes --]
* stmt.c (struct case_node): Added new member table_set.
(max_initialized): New flag.
(emit_case_nodes): Add new tree argument, handle case cclusters
separately.
(emit_case_table): New function, factored out of expand_case.
(scan_for_case_clusters): New.
(dump_case_nodes): New.
(check_tree): New.
(check_tree_1): New, called by check_tree.
(expand_case): Call scan_for_case_clusters, call emit_case_table.
(balance_case_nodes): Re-balance tree based on clusters identified
by scan_for_case_clusters.
--- stmt.c 2009-04-26 19:53:41.000000000 +0100
+++ stmt.c 2010-08-28 01:36:54.000000000 +0100
@@ -85,6 +85,7 @@ struct case_node
struct case_node *left; /* Left son in binary tree */
struct case_node *right; /* Right son in binary tree; also node chain */
struct case_node *parent; /* Parent of node in binary tree */
+ int table_set; /* 0 means binary test, else grouped by val */
tree low; /* Lowest index value for this label */
tree high; /* Highest index value for this label */
tree code_label; /* Label to jump to when node matches */
@@ -99,6 +100,7 @@ typedef struct case_node *case_node_ptr;
static short cost_table_[129];
static int use_cost_table;
static int cost_table_initialized;
+static int max_initialized;
/* Special care is needed because we allow -1, but TREE_INT_CST_LOW
is unsigned. */
@@ -120,9 +122,15 @@ static void balance_case_nodes (case_nod
static int node_has_low_bound (case_node_ptr, tree);
static int node_has_high_bound (case_node_ptr, tree);
static int node_is_bounded (case_node_ptr, tree);
-static void emit_case_nodes (rtx, case_node_ptr, rtx, tree);
+static int emit_case_nodes (rtx, tree, case_node_ptr, rtx, tree);
static struct case_node *add_case_node (struct case_node *, tree,
tree, tree, tree, alloc_pool);
+static void emit_case_table (tree, case_node_ptr, rtx, rtx, tree);
+static void scan_for_case_clusters (case_node *, tree);
+static void dump_case_nodes (struct case_node *, int);
+static int check_tree (case_node_ptr, int);
+static int check_tree_1 (case_node_ptr, unsigned long long int*,
+ long long int*, int unsignedp);
\f
/* Return the rtx-label that corresponds to a LABEL_DECL,
@@ -2150,6 +2158,23 @@ emit_case_bit_tests (tree index_type, tr
#define HAVE_tablejump 0
#endif
+static void
+dump_case_nodes(struct case_node *root, int indent)
+{
+ int h, l;
+ if (root == 0)
+ return;
+ dump_case_nodes (root->left, indent+3);
+ h = (int)TREE_INT_CST_LOW(root->high);
+ l = (int)TREE_INT_CST_LOW(root->low);
+ if (h == l)
+ fprintf (dump_file, "%*s%d", indent, "", l);
+ else
+ fprintf (dump_file, "%*s%d .. %d", indent, "", l, h);
+ fprintf (dump_file, " (%d)\n", root->table_set);
+ dump_case_nodes (root->right, indent+3);
+}
+
/* Terminate a case (Pascal/Ada) or switch (C) statement
in which ORIG_INDEX is the expression to be tested.
If ORIG_TYPE is not NULL, it is the original ORIG_INDEX
@@ -2164,9 +2189,6 @@ expand_case (tree exp)
struct case_node *n;
unsigned int count, uniq;
rtx index;
- rtx table_label;
- int ncases;
- rtx *labelvec;
int i;
rtx before_case, end, lab;
@@ -2291,6 +2313,14 @@ expand_case (tree exp)
/* Compute span of values. */
range = fold_build2 (MINUS_EXPR, index_type, maxval, minval);
+ if (dump_file)
+ fprintf (dump_file, "range low is %ld unique cases is %d count is %d pc rel %d\n",
+ TREE_INT_CST_LOW (range),
+ uniq,
+ count,
+ CASE_VECTOR_PC_RELATIVE);
+
+
/* Try implementing this switch statement by a short sequence of
bit-wise comparisons. However, we let the binary-tree case
below handle constant index expressions. */
@@ -2338,6 +2368,26 @@ expand_case (tree exp)
{
index = expand_normal (index_expr);
+ if (dump_file)
+ {
+ fprintf (dump_file, "Emitting Binary Decision Tree because ");
+ if (count < case_values_threshold ())
+ fprintf (dump_file, " Count [%d] < case_values_threshold [%d] \n",
+ count, case_values_threshold () );
+ else
+ if (compare_tree_int (range,
+ (optimize_insn_for_size_p () ? 3 : 10) * count) > 0 )
+ {
+ const char *msg = (optimize_insn_for_size_p () ? "3" : "10");
+ fprintf (dump_file, "Range %ld > %s [%d] * count [%d] \n",
+ TREE_INT_CST_LOW (range),
+ msg,
+ ((optimize_insn_for_size_p ()) ? 3 : 10),
+ count);
+
+ }
+ }
+
/* If the index is a short or char that we do not have
an insn to handle comparisons directly, convert it to
a full integer now, rather than letting each comparison
@@ -2377,90 +2427,60 @@ expand_case (tree exp)
use_cost_table
= (TREE_CODE (orig_type) != ENUMERAL_TYPE
&& estimate_case_costs (case_list));
+
+ if (dump_file)
+ {
+ fprintf (dump_file, "\n----- tree before scanning clusters\n");
+ dump_case_nodes (case_list, 0);
+ }
+
+ scan_for_case_clusters (case_list, index_type);
+
+ if (dump_file)
+ {
+ fprintf (dump_file, "\n----- tree after scanning clusters and before balancing.\n");
+ dump_case_nodes (case_list, 0);
+ }
+
balance_case_nodes (&case_list, NULL);
- emit_case_nodes (index, case_list, default_label, index_type);
- if (default_label)
+
+ if (dump_file)
+ {
+ fprintf (dump_file, "\n----- final tree\n");
+ dump_case_nodes (case_list, 0);
+ }
+
+ /* Check the Binary Decision Tree generated. */
+ if (check_tree (case_list, unsignedp))
+ {
+ if (dump_file)
+ fprintf (dump_file, "Bad Binary Search Tree created in %s\n",
+ current_function_name ());
+ error ("Bad Binary Search Tree. Check the dump by using -dq on the command line \n");
+
+ }
+ else
+ {
+ if (dump_file)
+ fprintf (dump_file, "Generated Binary Search Tree verified to be correct. \n");
+ max_initialized = 0;
+ }
+
+ if (emit_case_nodes (index, index_expr, case_list, default_label, index_type))
emit_jump (default_label);
+
}
else
{
rtx fallback_label = label_rtx (case_list->code_label);
- table_label = gen_label_rtx ();
- if (! try_casesi (index_type, index_expr, minval, range,
- table_label, default_label, fallback_label))
- {
- bool ok;
-
- /* Index jumptables from zero for suitable values of
- minval to avoid a subtraction. */
- if (optimize_insn_for_speed_p ()
- && compare_tree_int (minval, 0) > 0
- && compare_tree_int (minval, 3) < 0)
- {
- minval = build_int_cst (index_type, 0);
- range = maxval;
- }
-
- ok = try_tablejump (index_type, index_expr, minval, range,
- table_label, default_label);
- gcc_assert (ok);
- }
-
- /* Get table of labels to jump to, in order of case index. */
-
- ncases = tree_low_cst (range, 0) + 1;
- labelvec = XALLOCAVEC (rtx, ncases);
- memset (labelvec, 0, ncases * sizeof (rtx));
-
- for (n = case_list; n; n = n->right)
- {
- /* Compute the low and high bounds relative to the minimum
- value since that should fit in a HOST_WIDE_INT while the
- actual values may not. */
- HOST_WIDE_INT i_low
- = tree_low_cst (fold_build2 (MINUS_EXPR, index_type,
- n->low, minval), 1);
- HOST_WIDE_INT i_high
- = tree_low_cst (fold_build2 (MINUS_EXPR, index_type,
- n->high, minval), 1);
- HOST_WIDE_INT i;
-
- for (i = i_low; i <= i_high; i ++)
- labelvec[i]
- = gen_rtx_LABEL_REF (Pmode, label_rtx (n->code_label));
- }
-
- /* Fill in the gaps with the default. We may have gaps at
- the beginning if we tried to avoid the minval subtraction,
- so substitute some label even if the default label was
- deemed unreachable. */
- if (!default_label)
- default_label = fallback_label;
- for (i = 0; i < ncases; i++)
- if (labelvec[i] == 0)
- labelvec[i] = gen_rtx_LABEL_REF (Pmode, default_label);
-
- /* Output the table. */
- emit_label (table_label);
-
- if (CASE_VECTOR_PC_RELATIVE || flag_pic)
- emit_jump_insn (gen_rtx_ADDR_DIFF_VEC (CASE_VECTOR_MODE,
- gen_rtx_LABEL_REF (Pmode, table_label),
- gen_rtvec_v (ncases, labelvec),
- const0_rtx, const0_rtx));
- else
- emit_jump_insn (gen_rtx_ADDR_VEC (CASE_VECTOR_MODE,
- gen_rtvec_v (ncases, labelvec)));
-
- /* Record no drop-through after the table. */
- emit_barrier ();
+ emit_case_table (index_expr, case_list, default_label,
+ fallback_label, index_type);
}
before_case = NEXT_INSN (before_case);
end = get_last_insn ();
reorder_insns (before_case, end, start);
}
-
free_temp_slots ();
free_alloc_pool (case_node_pool);
}
@@ -2555,6 +2575,56 @@ estimate_case_costs (case_node_ptr node)
return 1;
}
+/* Scan a list of case values, group them into clusters which should
+ be emitted as tablejumps even when the overall case list indicates
+ a desicion tree. */
+
+static void
+scan_for_case_clusters (case_node *list, tree index_type)
+{
+ case_node *n, *l, *last_in_cluster;
+ unsigned int count;
+ tree min_case;
+ int table_set = 0;
+
+ list->parent = 0;
+ for (n=list; n; n=n->right)
+ {
+ n->table_set = 0;
+ if (n->right)
+ n->right->parent = n;
+ }
+
+ for (n=list; n; n=n->right)
+ {
+ min_case = n->low;
+ count = 0;
+ last_in_cluster = 0;
+ for (l=n; l; l=l->right)
+ {
+ count ++;
+ if (count > case_values_threshold ()
+ && compare_tree_int (fold (build2_stat (MINUS_EXPR, index_type,
+ l->high, min_case)),
+ (int)(optimize_size ? 3 : 10) * count) < 0)
+ last_in_cluster = l;
+ else if (last_in_cluster)
+ break;
+ }
+ if (last_in_cluster)
+ {
+ table_set ++;
+ for (l=n; l;)
+ {
+ l->table_set = table_set;
+ if (l == last_in_cluster)
+ break;
+ l = l->right;
+ }
+ n = last_in_cluster;
+ }
+ }
+}
/* Take an ordered list of case nodes
and transform them into a near optimal binary tree,
on the assumption that any target code selection value is as
@@ -2651,13 +2721,164 @@ balance_case_nodes (case_node_ptr *head,
npp = &(*npp)->right;
}
}
+ if ((*npp)->table_set)
+ {
+ /* We've selected a member of a dense cluster. Pick one
+ of the ends of the cluster so that we can later
+ isolate the cluster and emit a table for it. */
+ int set = (*npp)->table_set;
+ int near_start=0, near_end=0;
+ case_node *start_node, *end_node;
+ if (dump_file)
+ fprintf (dump_file, "Searching with set %d\n",
+ set);
+
+ /* Find the first and last member of the cluster. */
+ for (start_node = *npp;
+ (start_node->parent != parent)
+ && start_node->parent
+ && (start_node->parent->table_set == set);
+ start_node = start_node->parent)
+ {
+ if (dump_file)
+ {
+ fprintf (dump_file, "start_node is %ld\n",
+ TREE_INT_CST_LOW (start_node->low));
+ fprintf (dump_file, "parent is %ld\n",
+ (parent ? TREE_INT_CST_LOW (parent->low) : -1));
+ }
+ near_start ++;
+ }
+
+ for (end_node = *npp;
+ end_node->right
+ && (end_node->right->table_set == set);
+ end_node = end_node->right)
+ near_end ++;
+
+ if (dump_file)
+ fprintf (dump_file, "start %ld dist %d end %ld dist %d\n",
+ TREE_INT_CST_LOW (start_node->low), near_start,
+ TREE_INT_CST_LOW (end_node->low), near_end);
+
+ if (start_node->parent
+ && (start_node->parent != parent)
+ && (start_node->parent->table_set == 0))
+ {
+ if (dump_file)
+ fprintf (dump_file, "Start node changes to a node with table set 0 \n");
+
+ start_node = start_node->parent;
+ }
+ if (dump_file)
+ fprintf (dump_file, "start_node->parent %p (%ld) parent %p (%ld)\n",
+ start_node->parent,
+ (start_node->parent
+ ? TREE_INT_CST_LOW (start_node->parent->low) : -1),
+ parent,
+ (parent ? TREE_INT_CST_LOW (parent->low) : -1));
+
+ /* Watch out for end-of-list conditions. */
+ if (!start_node->parent || (start_node->parent == parent))
+ {
+ if (dump_file)
+ fprintf (dump_file, "start node is made to be empty.\n");
+
+ start_node = 0;
+ }
+ if (!end_node->right)
+ {
+ if (dump_file)
+ fprintf (dump_file, "end_node->right = empty\n");
+
+ end_node = 0;
+ }
+
+
+ /* This means that there's nothing left in the list but
+ the cluster; we keep it as-is and later emit a
+ tablejump for it. */
+ if ((!start_node && !end_node))
+ {
+ if (dump_file)
+ fprintf (dump_file, "dj: nothing left but the table\n");
+
+ return;
+ }
+
+ /* Move the selection to either before or after this
+ cluster, whichever is closer. */
+ if (!start_node || (near_end < near_start &&
+ (end_node && end_node->right)))
+ {
+ if (dump_file)
+ fprintf (dump_file, "Setting new parent to end node -> right\n");
+ npp = &(end_node->right);
+ }
+ else if (!start_node)
+ {
+ if (dump_file)
+ fprintf (dump_file, "setting new parent to head %p %ld\n",*head,
+ TREE_INT_CST_LOW ((*head)->low));
+
+ npp = head;
+ }
+ else
+ {
+ if (dump_file)
+ fprintf (dump_file, "setting new parent to start_node->parent->right\n");
+
+ npp = &(start_node->parent->right);
+ }
+
+ if (dump_file)
+ fprintf (dump_file, "dj: split moved to %ld\n", TREE_INT_CST_LOW ((*npp)->low));
+ /* FIXME:: Added this to correct case. */
+
+ if (left)
+ left->parent = NULL;
+
+ }
*head = np = *npp;
*npp = 0;
np->parent = parent;
np->left = left;
+ left->parent = np;
+ if (dump_file)
+ {
+ fprintf (dump_file, "Parent of left subtree is %p 0x%lx \n",
+ left->parent,
+ (left->parent) ? TREE_INT_CST_LOW (left->parent->low) : -1);
+
+ if (left->parent && left->parent->table_set)
+ fprintf (dump_file, "Caution: A cluster has been broken at 0x%lx\n",
+ (left->parent) ? TREE_INT_CST_LOW (left->parent->low) : -1);
+
+
+ fprintf (dump_file, "Setting left subtree to %p(0x%lx)\n",
+ left, (left ? TREE_INT_CST_LOW (left->low) : -1));
+
+ fprintf (dump_file, "Right is set to %p(%lx)\n",np->right,
+ (np->right ? TREE_INT_CST_LOW (np->right->low) : -1));
+
+
+ }
+ if (dump_file)
+ {
+ fprintf (dump_file, "details about np before balancing left\n");
+ fprintf (dump_file, "np = 0x%lx, np->parent = 0x%lx, ",
+ TREE_INT_CST_LOW (np->low),
+ np->parent ? TREE_INT_CST_LOW (np->parent->low) : -1);
+ fprintf (dump_file, "np->left->parent = 0x%lx\n",
+ np->left->parent ? TREE_INT_CST_LOW (np->left->parent->low) : -1);
+ fprintf (dump_file, "balancing left\n");
+
+ }
/* Optimize each of the two split parts. */
balance_case_nodes (&np->left, np);
+ if (dump_file)
+ fprintf (dump_file, "balancing right\n");
balance_case_nodes (&np->right, np);
}
else
@@ -2769,6 +2990,92 @@ node_has_high_bound (case_node_ptr node,
return 0;
}
+static void
+emit_case_table (tree index_expr, case_node_ptr node, rtx default_label,
+ rtx fallback_label, tree index_type)
+{
+ rtx table_label;
+ case_node *n;
+ int ncases;
+ rtx *labelvec;
+ int i;
+ tree minval, maxval, range;
+
+ for (n=node; n->right; n=n->right);
+
+ minval = node->low;
+ maxval = n->high;
+ range = fold_build2 (MINUS_EXPR, index_type, maxval, minval);
+
+
+ table_label = gen_label_rtx ();
+ if (! try_casesi (index_type, index_expr, minval, range,
+ table_label, default_label, fallback_label))
+ {
+ bool ok;
+
+ /* Index jumptables from zero for suitable values of
+ minval to avoid a subtraction. */
+ if (! optimize_size
+ && compare_tree_int (minval, 0) > 0
+ && compare_tree_int (minval, 3) < 0)
+ {
+ minval = build_int_cst (index_type, 0);
+ range = maxval;
+ }
+
+ ok = try_tablejump (index_type, index_expr, minval, range,
+ table_label, default_label);
+ gcc_assert (ok);
+ }
+
+ /* Get table of labels to jump to, in order of case index. */
+
+ ncases = tree_low_cst (range, 0) + 1;
+ labelvec = alloca (ncases * sizeof (rtx));
+ memset (labelvec, 0, ncases * sizeof (rtx));
+
+ for (n = node; n; n = n->right)
+ {
+ /* Compute the low and high bounds relative to the minimum
+ value since that should fit in a HOST_WIDE_INT while the
+ actual values may not. */
+ HOST_WIDE_INT i_low
+ = tree_low_cst (fold_build2 (MINUS_EXPR, index_type,
+ n->low, minval), 1);
+ HOST_WIDE_INT i_high
+ = tree_low_cst (fold_build2 (MINUS_EXPR, index_type,
+ n->high, minval), 1);
+ HOST_WIDE_INT i;
+
+ for (i = i_low; i <= i_high; i ++)
+ labelvec[i]
+ = gen_rtx_LABEL_REF (Pmode, label_rtx (n->code_label));
+ }
+
+ /* Fill in the gaps with the default. */
+ for (i = 0; i < ncases; i++)
+ if (labelvec[i] == 0)
+ labelvec[i] = gen_rtx_LABEL_REF (Pmode, default_label);
+
+
+ /* Output the table. */
+ emit_label (table_label);
+
+ if (CASE_VECTOR_PC_RELATIVE || flag_pic)
+ emit_jump_insn (gen_rtx_ADDR_DIFF_VEC (CASE_VECTOR_MODE,
+ gen_rtx_LABEL_REF (Pmode, table_label),
+ gen_rtvec_v (ncases, labelvec),
+ const0_rtx, const0_rtx));
+ else
+ emit_jump_insn (gen_rtx_ADDR_VEC (CASE_VECTOR_MODE,
+ gen_rtvec_v (ncases, labelvec)));
+
+ /* Record no drop-through after the table. */
+ emit_barrier ();
+
+}
+
/* 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. */
@@ -2806,18 +3113,47 @@ node_is_bounded (case_node_ptr node, tre
the possibility of a value greater than 51. If another parent
tests for the value 50, then this node need not test anything. */
-static void
-emit_case_nodes (rtx index, case_node_ptr node, rtx default_label,
+static int
+emit_case_nodes (rtx index, tree index_expr, case_node_ptr node, rtx default_label,
tree index_type)
{
/* If INDEX has an unsigned type, we must make unsigned branches. */
int unsignedp = TYPE_UNSIGNED (index_type);
+ int ret_val = 1;
enum machine_mode mode = GET_MODE (index);
enum machine_mode imode = TYPE_MODE (index_type);
/* Handle indices detected as constant during RTL expansion. */
if (mode == VOIDmode)
mode = imode;
+ /* If node->table_set is nonzero, then that node and all the
+ node->right in the chain represent a cluster of case nodes which
+ are appropriate for a tablejump. Note that node->left may also
+ have a cluster, so test for that too. */
+ if (node->table_set != 0 &&
+ node->right &&
+ node->table_set == node->right->table_set)
+ {
+ if (node->left)
+ {
+ tree test_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+
+ /* See if the value is on the right. */
+ emit_cmp_and_jump_insns (index,
+ convert_modes
+ (mode, imode,
+ expand_expr (node->low, NULL_RTX,
+ VOIDmode, 0),
+ unsignedp),
+ GE, NULL_RTX, mode, unsignedp,
+ label_rtx (test_label));
+ ret_val = emit_case_nodes (index, index_expr, node->left, default_label,
+ index_type);
+ expand_label (test_label);
+ }
+ emit_case_table (index_expr, node, default_label, default_label, index_type);
+ return 0;
+ }
/* See if our parents have already tested everything for us.
If they have, emit an unconditional jump for this node. */
@@ -2852,7 +3188,8 @@ emit_case_nodes (rtx index, case_node_pt
unsignedp),
GT, NULL_RTX, mode, unsignedp,
label_rtx (node->right->code_label));
- emit_case_nodes (index, node->left, default_label, index_type);
+ ret_val = emit_case_nodes (index, index_expr, node->left, default_label,
+ index_type);
}
else if (node_is_bounded (node->left, index_type))
@@ -2864,7 +3201,8 @@ emit_case_nodes (rtx index, case_node_pt
unsignedp),
LT, NULL_RTX, mode, unsignedp,
label_rtx (node->left->code_label));
- emit_case_nodes (index, node->right, default_label, index_type);
+ ret_val = emit_case_nodes (index, index_expr, node->right, default_label,
+ index_type);
}
/* If both children are single-valued cases with no
@@ -2915,17 +3253,19 @@ emit_case_nodes (rtx index, case_node_pt
GT, NULL_RTX, mode, unsignedp,
label_rtx (test_label));
- /* Value must be on the left.
+ /* Value must be on the left.
Handle the left-hand subtree. */
- emit_case_nodes (index, node->left, default_label, index_type);
+ ret_val = emit_case_nodes (index, index_expr, node->left, default_label,
+ index_type);
/* If left-hand subtree does nothing,
go to default. */
- if (default_label)
- emit_jump (default_label);
+ if (ret_val && default_label)
+ emit_jump (default_label);
/* Code branches here for the right-hand subtree. */
expand_label (test_label);
- emit_case_nodes (index, node->right, default_label, index_type);
+ ret_val = emit_case_nodes (index, index_expr, node->right, default_label,
+ index_type);
}
}
@@ -2952,7 +3292,8 @@ emit_case_nodes (rtx index, case_node_pt
default_label);
}
- emit_case_nodes (index, node->right, default_label, index_type);
+ ret_val = emit_case_nodes (index, index_expr, node->right, default_label,
+ index_type);
}
else
/* We cannot process node->right normally
@@ -2983,7 +3324,8 @@ emit_case_nodes (rtx index, case_node_pt
default_label);
}
- emit_case_nodes (index, node->left, default_label, index_type);
+ ret_val = emit_case_nodes (index, index_expr, node->left, default_label,
+ index_type);
}
else
/* We cannot process node->left normally
@@ -3048,7 +3390,7 @@ emit_case_nodes (rtx index, case_node_pt
label_rtx (node->code_label));
/* Handle the left-hand subtree. */
- emit_case_nodes (index, node->left, default_label, index_type);
+ ret_val = emit_case_nodes (index, index_expr, node->left, default_label, index_type);
/* If right node had to be handled later, do that now. */
@@ -3056,11 +3398,11 @@ emit_case_nodes (rtx index, case_node_pt
{
/* If the left-hand subtree fell through,
don't let it fall into the right-hand subtree. */
- if (default_label)
- emit_jump (default_label);
+ if (ret_val && default_label)
+ emit_jump (default_label);
expand_label (test_label);
- emit_case_nodes (index, node->right, default_label, index_type);
+ ret_val = emit_case_nodes (index, index_expr, node->right, default_label, index_type);
}
}
@@ -3089,7 +3431,7 @@ emit_case_nodes (rtx index, case_node_pt
LE, NULL_RTX, mode, unsignedp,
label_rtx (node->code_label));
- emit_case_nodes (index, node->right, default_label, index_type);
+ ret_val = emit_case_nodes (index, index_expr, node->right, default_label, index_type);
}
else if (node->right == 0 && node->left != 0)
@@ -3117,7 +3459,8 @@ emit_case_nodes (rtx index, case_node_pt
GE, NULL_RTX, mode, unsignedp,
label_rtx (node->code_label));
- emit_case_nodes (index, node->left, default_label, index_type);
+ ret_val = emit_case_nodes (index, index_expr, node->left, default_label,
+ index_type);
}
else
@@ -3174,4 +3517,147 @@ emit_case_nodes (rtx index, case_node_pt
emit_jump (label_rtx (node->code_label));
}
}
+
+ return ret_val;
}
+
+/* Subroutine of check_tree.
+ Performs inorder traversal of the tree rooted at NODE. MAX is the last
+ value that would have been printed, if we were to print nodes ( inorder
+ traversal). Check if MAX is greater than node->high, if Yes, Return 1
+ indicating a bad Binary Search Tree. Check Whether the parent
+ pointer of each child points to node. If not, Return 1, indicating a
+ bad Tree. Return 0, If the tree is correct. */
+static
+int check_tree_1 (case_node_ptr node, unsigned long long int *maxu, long long int* maxi, int unsignedp)
+{
+ unsigned long long int hu;
+ long long int hi;
+
+ if (! node)
+ return 0;
+
+ /* check the left subtree */
+ if (check_tree_1 (node->left, maxu, maxi, unsignedp))
+ return 1;
+
+ if (unsignedp)
+ {
+ unsigned int hi_part = TREE_INT_CST_HIGH (node->high);
+ unsigned int lo_part = TREE_INT_CST_LOW (node->high);
+
+ hu = ((unsigned long long int)hi_part << 32) | lo_part;
+ }
+ else
+ {
+ int hi_part = TREE_INT_CST_HIGH (node->high);
+ int lo_part = TREE_INT_CST_LOW (node->high);
+
+ hi = ((long long int)hi_part << 32) | lo_part;
+ }
+
+ /* Check if the tree is correct in terms of the values of the nodes. */
+ if (!max_initialized)
+ {
+ /* We have reached the leftmost node of the tree. */
+ if (unsignedp)
+ *maxu = hu;
+ else
+ *maxi = hi;
+ max_initialized = 1;
+ }
+ else if ((unsignedp && (*maxu < hu)) || (!unsignedp && (*maxi < hi)))
+ {
+ if (unsignedp)
+ *maxu = hu;
+ else
+ *maxi = hi;
+ }
+ else
+ {
+ if (dump_file)
+ {
+ if (unsignedp)
+ {
+ fprintf (dump_file, "hu = 0x%llx, hu = %llu (unsigned), *maxu = 0x%llx, *maxu (decimal) = 0x%llu (unsigned)\n",
+ hu, hu, *maxu, *maxu );
+ fprintf (dump_file, "PROBLEM: maxu is greater than hu, when it should not be so.\n" );
+ }
+ else
+ {
+ fprintf (dump_file, "hi = 0x%llx, hi = %lld (signed), *maxi = 0x%llx, *maxi (decimal) = 0x%llx (signed)\n",
+ hi, hi, *maxi, *maxi );
+ fprintf (dump_file, "PROBLEM: maxi is greater than hi, when it should not be so.\n" );
+ }
+ }
+ return 1;
+ }
+ /* Check to see if the pointers in each node are sane */
+ if ((node->left && (!(node->left->parent == node))) || (node->right && (!(node->right->parent == node))))
+ {
+ if (dump_file)
+ {
+ if (unsignedp)
+ {
+ fprintf (dump_file, "PROBLEM: The parent pointers of children do not point to the correct"
+ "pointer for the following\n");
+ fprintf (dump_file, "Parent (Hex) = 0x%lx, Parent (Decimal) = %lu (unsigned)\n", TREE_INT_CST_LOW (node->low),
+ TREE_INT_CST_LOW (node->low));
+ fprintf (dump_file, "Left Child (Hex) = 0x%lx, Left Child (Decimal) = %lu (unsigned)\n",
+ node->left?TREE_INT_CST_LOW (node->left->low):-1,node->left?TREE_INT_CST_LOW (node->left->low):-1);
+ fprintf (dump_file, "Left Child's Parent (Hex) = 0x%lx, Left Child's Parent (Decimal) = %lu (unsigned)\n",
+ node->left?node->left->parent?TREE_INT_CST_LOW (node->left->parent->low):-1:-1,
+ node->left?node->left->parent?TREE_INT_CST_LOW (node->left->parent->low):-1:-1);
+ fprintf (dump_file, "Right Child (Hex) = 0x%lx, Right Child (Decimal) = %lu (unsigned)\n",
+ node->right?TREE_INT_CST_LOW (node->right->low):-1,node->right?TREE_INT_CST_LOW (node->right->low):-1);
+ fprintf (dump_file, "Right Child's Parent (Hex) = 0x%lx, Right Child's Parent (Decimal) = %lu (unsigned)\n",
+ node->right?node->right->parent?TREE_INT_CST_LOW (node->right->parent->low):-1:-1,
+ node->right?node->right->parent?TREE_INT_CST_LOW (node->right->parent->low):-1:-1);
+ fprintf (dump_file, "If the value of a node is shown to be -1 then it means that the case value is actually"
+ " -1 or that the pointer points to nothing i.e is NULL\n");
+ }
+ else
+ {
+
+ fprintf (dump_file, "PROBLEM: The parent pointers of children do not point to the correct"
+ "pointer for the following\n");
+ fprintf (dump_file, "Parent (Hex) = 0x%lx, Parent (Decimal) = %ld (signed)\n", TREE_INT_CST_LOW (node->low),
+ TREE_INT_CST_LOW (node->low));
+ fprintf (dump_file, "Left Child (Hex) = 0x%lx, Left Child (Decimal) = %ld (signed)\n",
+ node->left?TREE_INT_CST_LOW (node->left->low):-1,node->left?TREE_INT_CST_LOW (node->left->low):-1);
+ fprintf (dump_file, "Left Child's Parent (Hex) = 0x%lx, Left Child's Parent (Decimal) = %ld (signed)\n",
+ node->left?node->left->parent?TREE_INT_CST_LOW (node->left->parent->low):-1:-1,
+ node->left?node->left->parent?TREE_INT_CST_LOW (node->left->parent->low):-1:-1);
+ fprintf (dump_file, "Right Child (Hex) = 0x%lx, Right Child (Decimal) = %ld (signed)\n",
+ node->right?TREE_INT_CST_LOW (node->right->low):-1,node->right?TREE_INT_CST_LOW (node->right->low):-1);
+ fprintf (dump_file, "Right Child's Parent (Hex) = 0x%lx, Right Child's Parent (Decimal) = %ld (signed)\n",
+ node->right?node->right->parent?TREE_INT_CST_LOW (node->right->parent->low):-1:-1,
+ node->right?node->right->parent?TREE_INT_CST_LOW (node->right->parent->low):-1:-1);
+ fprintf (dump_file, "If the value of a node is shown to be -1 then it means that the case value is actually"
+ " -1 or that the pointer points to nothing i.e is NULL\n");
+ }
+ }
+
+ return 1;
+ }
+
+/* Check the right subtree. */
+ if (check_tree_1 (node->right, maxu, maxi, unsignedp))
+ return 1;
+
+ return 0;
+}
+
+
+static
+int check_tree (case_node_ptr head, int unsignedp)
+{
+ unsigned long long int max_u_inorder=0;
+ long long int max_i_inorder = 0;
+/* max_initialized is set to 1 when we reach the leftmost node of the tree. */
+ max_initialized = 0;
+ if (dump_file)
+ fprintf (dump_file, "Checking the generated BST\n");
+ return check_tree_1 (head, &max_u_inorder, &max_i_inorder, unsignedp);
+}
+
next prev parent reply other threads:[~2010-08-31 10:00 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-08-27 13:49 Paulo J. Matos
2010-08-27 15:03 ` Ian Lance Taylor
2010-08-27 15:09 ` Paulo J. Matos
2010-08-27 15:27 ` Richard Guenther
2010-08-28 0:21 ` Xinliang David Li
2010-08-28 11:08 ` Paulo J. Matos
2010-08-31 15:59 ` Rahul Kharche [this message]
[not found] ` <201009010034.18924.paul@codesourcery.com>
2010-09-01 8:39 ` Richard Guenther
2010-09-01 9:15 ` Paulo J. Matos
2010-09-01 9:33 ` Richard Guenther
2010-09-01 12:37 ` Paulo J. Matos
[not found] ` <D84AB18A31AC674EBE9B5300634A800601BF0B0932@EXCHANGEVS.IceraSemi.local>
[not found] ` <AANLkTinFhrgJw3Wz8aLhBU6PMYpJzBFTRxLUH3eoz4M0@mail.gmail.com>
[not found] ` <4D60B0700D1DB54A8C0C6E9BE691637008965A28@EXCHANGEVS.IceraSemi.local>
[not found] ` <AANLkTinkjc4Y9baHXXK7v3ibQNwMtwGhA_oGmaFbykkA@mail.gmail.com>
2010-09-03 10:29 ` Rahul Kharche
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4D60B0700D1DB54A8C0C6E9BE6916370106C745A@EXCHANGEVS.IceraSemi.local \
--to=rahul@icerasemi.com \
--cc=gcc@gcc.gnu.org \
--cc=pocmatos@gmail.com \
--cc=sdkteam-gnu@IceraSemi.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).