Commit b7814a18 by Richard Guenther Committed by Richard Biener

re PR tree-optimization/14495 ([tree-ssa] Propagate range info into a switch statement)

2008-04-02  Richard Guenther  <rguenther@suse.de>

	PR tree-optimization/14495
	PR tree-optimization/34793
	* tree-vrp.c (struct switch_update): New structure.
	(to_remove_edges, to_update_switch_stmts): New VECs.
	(simplify_switch_using_ranges): New function.  Remove not taken
	case labels and edges.
	(simplify_stmt_using_ranges): Call it.
	(identify_jump_threads): Mark edges we have queued for removal
	so we don't thread them.
	(execute_vrp): Remove edges queued for removal, update SWITCH_STMT
	case label vector.
	* tree-cfg.c (group_case_labels): Deal with missing default label.
	(tree_verify_flow_info): Allow missing default label.
	* stmt.c (emit_case_bit_tests): Deal with NULL default_label.
	(emit_case_nodes): Likewise.
	(expand_case): Do not rely on the default label to be present.
	* expr.c (try_casesi): Deal with NULL default_label.
	(do_tablejump): Likewise.

	* gcc.dg/tree-ssa/vrp41.c: New testcase.
	* gcc.dg/tree-ssa/vrp42.c: Likewise.

From-SVN: r133835
parent 8aea0bf0
2008-04-02 Richard Guenther <rguenther@suse.de> 2008-04-02 Richard Guenther <rguenther@suse.de>
PR tree-optimization/14495 PR tree-optimization/14495
PR tree-optimization/34793
* tree-vrp.c (struct switch_update): New structure.
(to_remove_edges, to_update_switch_stmts): New VECs.
(simplify_switch_using_ranges): New function. Remove not taken
case labels and edges.
(simplify_stmt_using_ranges): Call it.
(identify_jump_threads): Mark edges we have queued for removal
so we don't thread them.
(execute_vrp): Remove edges queued for removal, update SWITCH_STMT
case label vector.
* tree-cfg.c (group_case_labels): Deal with missing default label.
(tree_verify_flow_info): Allow missing default label.
* stmt.c (emit_case_bit_tests): Deal with NULL default_label.
(emit_case_nodes): Likewise.
(expand_case): Do not rely on the default label to be present.
* expr.c (try_casesi): Deal with NULL default_label.
(do_tablejump): Likewise.
2008-04-02 Richard Guenther <rguenther@suse.de>
PR tree-optimization/14495
* tree-vrp.c (vrp_visit_cond_stmt): Do not handle * tree-vrp.c (vrp_visit_cond_stmt): Do not handle
SWITCH_EXPR here ... SWITCH_EXPR here ...
(vrp_visit_switch_stmt): ... but here (new function). (vrp_visit_switch_stmt): ... but here (new function).
......
...@@ -9851,8 +9851,9 @@ try_casesi (tree index_type, tree index_expr, tree minval, tree range, ...@@ -9851,8 +9851,9 @@ try_casesi (tree index_type, tree index_expr, tree minval, tree range,
index_expr, minval); index_expr, minval);
minval = integer_zero_node; minval = integer_zero_node;
index = expand_normal (index_expr); index = expand_normal (index_expr);
emit_cmp_and_jump_insns (rangertx, index, LTU, NULL_RTX, if (default_label)
omode, 1, default_label); emit_cmp_and_jump_insns (rangertx, index, LTU, NULL_RTX,
omode, 1, default_label);
/* Now we can safely truncate. */ /* Now we can safely truncate. */
index = convert_to_mode (index_mode, index, 0); index = convert_to_mode (index_mode, index, 0);
} }
...@@ -9931,8 +9932,9 @@ do_tablejump (rtx index, enum machine_mode mode, rtx range, rtx table_label, ...@@ -9931,8 +9932,9 @@ do_tablejump (rtx index, enum machine_mode mode, rtx range, rtx table_label,
or equal to the minimum value of the range and less than or equal to or equal to the minimum value of the range and less than or equal to
the maximum value of the range. */ the maximum value of the range. */
emit_cmp_and_jump_insns (index, range, GTU, NULL_RTX, mode, 1, if (default_label)
default_label); emit_cmp_and_jump_insns (index, range, GTU, NULL_RTX, mode, 1,
default_label);
/* If index is in range, it must fit in Pmode. /* If index is in range, it must fit in Pmode.
Convert to Pmode so we can index with it. */ Convert to Pmode so we can index with it. */
......
...@@ -2258,8 +2258,9 @@ emit_case_bit_tests (tree index_type, tree index_expr, tree minval, ...@@ -2258,8 +2258,9 @@ emit_case_bit_tests (tree index_type, tree index_expr, tree minval,
mode = TYPE_MODE (index_type); mode = TYPE_MODE (index_type);
expr = expand_normal (range); expr = expand_normal (range);
emit_cmp_and_jump_insns (index, expr, GTU, NULL_RTX, mode, 1, if (default_label)
default_label); emit_cmp_and_jump_insns (index, expr, GTU, NULL_RTX, mode, 1,
default_label);
index = convert_to_mode (word_mode, index, 0); index = convert_to_mode (word_mode, index, 0);
index = expand_binop (word_mode, ashl_optab, const1_rtx, index = expand_binop (word_mode, ashl_optab, const1_rtx,
...@@ -2274,7 +2275,8 @@ emit_case_bit_tests (tree index_type, tree index_expr, tree minval, ...@@ -2274,7 +2275,8 @@ emit_case_bit_tests (tree index_type, tree index_expr, tree minval,
word_mode, 1, test[i].label); word_mode, 1, test[i].label);
} }
emit_jump (default_label); if (default_label)
emit_jump (default_label);
} }
#ifndef HAVE_casesi #ifndef HAVE_casesi
...@@ -2320,7 +2322,7 @@ expand_case (tree exp) ...@@ -2320,7 +2322,7 @@ expand_case (tree exp)
struct case_node *case_list = 0; struct case_node *case_list = 0;
/* Label to jump to if no case matches. */ /* Label to jump to if no case matches. */
tree default_label_decl; tree default_label_decl = NULL_TREE;
alloc_pool case_node_pool = create_alloc_pool ("struct case_node pool", alloc_pool case_node_pool = create_alloc_pool ("struct case_node pool",
sizeof (struct case_node), sizeof (struct case_node),
...@@ -2338,18 +2340,21 @@ expand_case (tree exp) ...@@ -2338,18 +2340,21 @@ expand_case (tree exp)
{ {
tree elt; tree elt;
bitmap label_bitmap; bitmap label_bitmap;
int vl = TREE_VEC_LENGTH (vec);
/* cleanup_tree_cfg removes all SWITCH_EXPR with their index /* cleanup_tree_cfg removes all SWITCH_EXPR with their index
expressions being INTEGER_CST. */ expressions being INTEGER_CST. */
gcc_assert (TREE_CODE (index_expr) != INTEGER_CST); gcc_assert (TREE_CODE (index_expr) != INTEGER_CST);
/* The default case is at the end of TREE_VEC. */ /* The default case, if ever taken, is at the end of TREE_VEC. */
elt = TREE_VEC_ELT (vec, TREE_VEC_LENGTH (vec) - 1); elt = TREE_VEC_ELT (vec, vl - 1);
gcc_assert (!CASE_HIGH (elt)); if (!CASE_LOW (elt) && !CASE_HIGH (elt))
gcc_assert (!CASE_LOW (elt)); {
default_label_decl = CASE_LABEL (elt); default_label_decl = CASE_LABEL (elt);
--vl;
}
for (i = TREE_VEC_LENGTH (vec) - 1; --i >= 0; ) for (i = vl - 1; i >= 0; --i)
{ {
tree low, high; tree low, high;
elt = TREE_VEC_ELT (vec, i); elt = TREE_VEC_ELT (vec, i);
...@@ -2368,7 +2373,8 @@ expand_case (tree exp) ...@@ -2368,7 +2373,8 @@ expand_case (tree exp)
before_case = start = get_last_insn (); before_case = start = get_last_insn ();
default_label = label_rtx (default_label_decl); if (default_label_decl)
default_label = label_rtx (default_label_decl);
/* Get upper and lower bounds of case values. */ /* Get upper and lower bounds of case values. */
...@@ -2413,7 +2419,8 @@ expand_case (tree exp) ...@@ -2413,7 +2419,8 @@ expand_case (tree exp)
type, so we may still get a zero here. */ type, so we may still get a zero here. */
if (count == 0) if (count == 0)
{ {
emit_jump (default_label); if (default_label)
emit_jump (default_label);
free_alloc_pool (case_node_pool); free_alloc_pool (case_node_pool);
return; return;
} }
...@@ -2509,7 +2516,8 @@ expand_case (tree exp) ...@@ -2509,7 +2516,8 @@ expand_case (tree exp)
&& estimate_case_costs (case_list)); && estimate_case_costs (case_list));
balance_case_nodes (&case_list, NULL); balance_case_nodes (&case_list, NULL);
emit_case_nodes (index, case_list, default_label, index_type); emit_case_nodes (index, case_list, default_label, index_type);
emit_jump (default_label); if (default_label)
emit_jump (default_label);
} }
else else
{ {
...@@ -2559,9 +2567,10 @@ expand_case (tree exp) ...@@ -2559,9 +2567,10 @@ expand_case (tree exp)
} }
/* Fill in the gaps with the default. */ /* Fill in the gaps with the default. */
for (i = 0; i < ncases; i++) if (default_label)
if (labelvec[i] == 0) for (i = 0; i < ncases; i++)
labelvec[i] = gen_rtx_LABEL_REF (Pmode, default_label); if (labelvec[i] == 0)
labelvec[i] = gen_rtx_LABEL_REF (Pmode, default_label);
/* Output the table. */ /* Output the table. */
emit_label (table_label); emit_label (table_label);
...@@ -3043,7 +3052,8 @@ emit_case_nodes (rtx index, case_node_ptr node, rtx default_label, ...@@ -3043,7 +3052,8 @@ emit_case_nodes (rtx index, case_node_ptr node, rtx default_label,
emit_case_nodes (index, node->left, default_label, index_type); emit_case_nodes (index, node->left, default_label, index_type);
/* If left-hand subtree does nothing, /* If left-hand subtree does nothing,
go to default. */ go to default. */
emit_jump (default_label); if (default_label)
emit_jump (default_label);
/* Code branches here for the right-hand subtree. */ /* Code branches here for the right-hand subtree. */
expand_label (test_label); expand_label (test_label);
...@@ -3178,7 +3188,8 @@ emit_case_nodes (rtx index, case_node_ptr node, rtx default_label, ...@@ -3178,7 +3188,8 @@ emit_case_nodes (rtx index, case_node_ptr node, rtx default_label,
{ {
/* If the left-hand subtree fell through, /* If the left-hand subtree fell through,
don't let it fall into the right-hand subtree. */ don't let it fall into the right-hand subtree. */
emit_jump (default_label); if (default_label)
emit_jump (default_label);
expand_label (test_label); expand_label (test_label);
emit_case_nodes (index, node->right, default_label, index_type); emit_case_nodes (index, node->right, default_label, index_type);
......
2008-04-02 Richard Guenther <rguenther@suse.de> 2008-04-02 Richard Guenther <rguenther@suse.de>
PR tree-optimization/14495 PR tree-optimization/14495
PR tree-optimization/34793
* gcc.dg/tree-ssa/vrp41.c: New testcase.
* gcc.dg/tree-ssa/vrp42.c: Likewise.
2008-04-02 Richard Guenther <rguenther@suse.de>
PR tree-optimization/14495
* gcc.dg/tree-ssa/vrp40.c: New testcase. * gcc.dg/tree-ssa/vrp40.c: New testcase.
2008-04-02 Eric Botcazou <ebotcazou@adacore.com> 2008-04-02 Eric Botcazou <ebotcazou@adacore.com>
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp1" } */
void bar0 (void);
void bar1 (void);
void bar2 (void);
void bar3 (void);
void
foo (int a)
{
if (a < 100)
return;
if (200 < a)
return;
switch (a)
{
case 99: bar0 (); return;
case 100: bar1 (); return;
case 101: bar2 (); return;
case 102: bar3 (); return;
}
}
/* { dg-final { scan-tree-dump-not "case 99:" "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -Wuninitialized" } */
int foo(int val)
{
int tmp;
if ((val > 5) && (val < 8))
{
switch (val)
{
case 6:
tmp = 1;
break;
case 7:
tmp = 2;
break;
}
return tmp; /* { dg-bogus "used uninitialized" } */
}
return 0;
}
...@@ -1060,18 +1060,23 @@ group_case_labels (void) ...@@ -1060,18 +1060,23 @@ group_case_labels (void)
tree labels = SWITCH_LABELS (stmt); tree labels = SWITCH_LABELS (stmt);
int old_size = TREE_VEC_LENGTH (labels); int old_size = TREE_VEC_LENGTH (labels);
int i, j, new_size = old_size; int i, j, new_size = old_size;
tree default_case = TREE_VEC_ELT (labels, old_size - 1); tree default_case = NULL_TREE;
tree default_label; tree default_label = NULL_TREE;
/* The default label is always the last case in a switch /* The default label is always the last case in a switch
statement after gimplification. */ statement after gimplification if it was not optimized
default_label = CASE_LABEL (default_case); away. */
if (!CASE_LOW (TREE_VEC_ELT (labels, old_size - 1))
&& !CASE_HIGH (TREE_VEC_ELT (labels, old_size - 1)))
{
default_case = TREE_VEC_ELT (labels, old_size - 1);
default_label = CASE_LABEL (default_case);
old_size--;
}
/* Look for possible opportunities to merge cases. /* Look for possible opportunities to merge cases. */
Ignore the last element of the label vector because it
must be the default case. */
i = 0; i = 0;
while (i < old_size - 1) while (i < old_size)
{ {
tree base_case, base_label, base_high; tree base_case, base_label, base_high;
base_case = TREE_VEC_ELT (labels, i); base_case = TREE_VEC_ELT (labels, i);
...@@ -1095,7 +1100,7 @@ group_case_labels (void) ...@@ -1095,7 +1100,7 @@ group_case_labels (void)
/* Try to merge case labels. Break out when we reach the end /* Try to merge case labels. Break out when we reach the end
of the label vector or when we cannot merge the next case of the label vector or when we cannot merge the next case
label with the current one. */ label with the current one. */
while (i < old_size - 1) while (i < old_size)
{ {
tree merge_case = TREE_VEC_ELT (labels, i); tree merge_case = TREE_VEC_ELT (labels, i);
tree merge_label = CASE_LABEL (merge_case); tree merge_label = CASE_LABEL (merge_case);
...@@ -4604,13 +4609,16 @@ tree_verify_flow_info (void) ...@@ -4604,13 +4609,16 @@ tree_verify_flow_info (void)
/* Verify that the case labels are sorted. */ /* Verify that the case labels are sorted. */
prev = TREE_VEC_ELT (vec, 0); prev = TREE_VEC_ELT (vec, 0);
for (i = 1; i < n - 1; ++i) for (i = 1; i < n; ++i)
{ {
tree c = TREE_VEC_ELT (vec, i); tree c = TREE_VEC_ELT (vec, i);
if (! CASE_LOW (c)) if (! CASE_LOW (c))
{ {
error ("found default case not at end of case vector"); if (i != n - 1)
err = 1; {
error ("found default case not at end of case vector");
err = 1;
}
continue; continue;
} }
if (! tree_int_cst_lt (CASE_LOW (prev), CASE_LOW (c))) if (! tree_int_cst_lt (CASE_LOW (prev), CASE_LOW (c)))
...@@ -4624,11 +4632,9 @@ tree_verify_flow_info (void) ...@@ -4624,11 +4632,9 @@ tree_verify_flow_info (void)
} }
prev = c; prev = c;
} }
if (CASE_LOW (TREE_VEC_ELT (vec, n - 1))) /* VRP will remove the default case if it can prove it will
{ never be executed. So do not verify there always exists
error ("no default case found at end of case vector"); a default case here. */
err = 1;
}
FOR_EACH_EDGE (e, ei, bb->succs) FOR_EACH_EDGE (e, ei, bb->succs)
{ {
......
...@@ -104,6 +104,16 @@ static value_range_t **vr_value; ...@@ -104,6 +104,16 @@ static value_range_t **vr_value;
node. */ node. */
static int *vr_phi_edge_counts; static int *vr_phi_edge_counts;
typedef struct {
tree stmt;
tree vec;
} switch_update;
static VEC (edge, heap) *to_remove_edges;
DEF_VEC_O(switch_update);
DEF_VEC_ALLOC_O(switch_update, heap);
static VEC (switch_update, heap) *to_update_switch_stmts;
/* Return the maximum value for TYPEs base type. */ /* Return the maximum value for TYPEs base type. */
...@@ -6298,6 +6308,106 @@ simplify_cond_using_ranges (tree stmt) ...@@ -6298,6 +6308,106 @@ simplify_cond_using_ranges (tree stmt)
} }
} }
/* Simplify a switch statement using the value range of the switch
argument. */
static void
simplify_switch_using_ranges (tree stmt)
{
tree op = TREE_OPERAND (stmt, 0);
value_range_t *vr;
bool take_default;
edge e;
edge_iterator ei;
size_t i = 0, j = 0, n, n2;
tree vec, vec2;
switch_update su;
if (TREE_CODE (op) != SSA_NAME)
return;
vr = get_value_range (op);
/* We can only handle integer ranges. */
if (vr->type != VR_RANGE
|| symbolic_range_p (vr))
return;
/* Find case label for min/max of the value range. */
vec = SWITCH_LABELS (stmt);
n = TREE_VEC_LENGTH (vec);
take_default = !find_case_label_index (vec, 0, vr->min, &i);
take_default |= !find_case_label_index (vec, i, vr->max, &j);
/* If the case label range is continuous, we do not need to
preserve the default case label. Verify that. */
if (!take_default && j > i)
{
tree low, high;
size_t k;
high = CASE_LOW (TREE_VEC_ELT (vec, i));
if (CASE_HIGH (TREE_VEC_ELT (vec, i)))
high = CASE_HIGH (TREE_VEC_ELT (vec, i));
for (k = i + 1; k <= j; ++k)
{
low = CASE_LOW (TREE_VEC_ELT (vec, k));
if (!integer_onep (int_const_binop (MINUS_EXPR, low, high, 0)))
{
take_default = true;
break;
}
high = low;
if (CASE_HIGH (TREE_VEC_ELT (vec, k)))
high = CASE_HIGH (TREE_VEC_ELT (vec, k));
}
}
/* Bail out if this is just all edges taken. */
if (i == 0
&& j == n - 2
&& take_default)
return;
/* Build a new vector of taken case labels. */
vec2 = make_tree_vec (j - i + 1 + (int)take_default);
for (n2 = 0; i <= j; ++i, ++n2)
TREE_VEC_ELT (vec2, n2) = TREE_VEC_ELT (vec, i);
/* Add the default edge, if necessary. */
if (take_default)
TREE_VEC_ELT (vec2, n2++) = TREE_VEC_ELT (vec, n - 1);
/* Mark needed edges. */
for (i = 0; i < n2; ++i)
{
e = find_edge (bb_for_stmt (stmt),
label_to_block (CASE_LABEL (TREE_VEC_ELT (vec2, i))));
e->aux = (void *)-1;
}
/* Queue not needed edges for later removal. */
FOR_EACH_EDGE (e, ei, bb_for_stmt (stmt)->succs)
{
if (e->aux == (void *)-1)
{
e->aux = NULL;
continue;
}
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "removing unreachable case label\n");
}
VEC_safe_push (edge, heap, to_remove_edges, e);
}
/* And queue an update for the stmt. */
su.stmt = stmt;
su.vec = vec2;
VEC_safe_push (switch_update, heap, to_update_switch_stmts, &su);
}
/* Simplify STMT using ranges if possible. */ /* Simplify STMT using ranges if possible. */
void void
...@@ -6324,9 +6434,9 @@ simplify_stmt_using_ranges (tree stmt) ...@@ -6324,9 +6434,9 @@ simplify_stmt_using_ranges (tree stmt)
} }
else if (TREE_CODE (stmt) == COND_EXPR else if (TREE_CODE (stmt) == COND_EXPR
&& COMPARISON_CLASS_P (COND_EXPR_COND (stmt))) && COMPARISON_CLASS_P (COND_EXPR_COND (stmt)))
{ simplify_cond_using_ranges (stmt);
simplify_cond_using_ranges (stmt); else if (TREE_CODE (stmt) == SWITCH_EXPR)
} simplify_switch_using_ranges (stmt);
} }
/* Stack of dest,src equivalency pairs that need to be restored after /* Stack of dest,src equivalency pairs that need to be restored after
...@@ -6378,6 +6488,8 @@ identify_jump_threads (void) ...@@ -6378,6 +6488,8 @@ identify_jump_threads (void)
{ {
basic_block bb; basic_block bb;
tree dummy; tree dummy;
int i;
edge e;
/* Ugh. When substituting values earlier in this pass we can /* Ugh. When substituting values earlier in this pass we can
wipe the dominance information. So rebuild the dominator wipe the dominance information. So rebuild the dominator
...@@ -6391,6 +6503,11 @@ identify_jump_threads (void) ...@@ -6391,6 +6503,11 @@ identify_jump_threads (void)
recompute it. */ recompute it. */
mark_dfs_back_edges (); mark_dfs_back_edges ();
/* Do not thread across edges we are about to remove. Just marking
them as EDGE_DFS_BACK will do. */
for (i = 0; VEC_iterate (edge, to_remove_edges, i, e); ++i)
e->flags |= EDGE_DFS_BACK;
/* Allocate our unwinder stack to unwind any temporary equivalences /* Allocate our unwinder stack to unwind any temporary equivalences
that might be recorded. */ that might be recorded. */
stack = VEC_alloc (tree, heap, 20); stack = VEC_alloc (tree, heap, 20);
...@@ -6436,7 +6553,6 @@ identify_jump_threads (void) ...@@ -6436,7 +6553,6 @@ identify_jump_threads (void)
&& INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (cond, 1))))) && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (cond, 1)))))
{ {
edge_iterator ei; edge_iterator ei;
edge e;
/* We've got a block with multiple predecessors and multiple /* We've got a block with multiple predecessors and multiple
successors which also ends in a suitable conditional. For successors which also ends in a suitable conditional. For
...@@ -6603,6 +6719,10 @@ record_numbers_of_iterations (void) ...@@ -6603,6 +6719,10 @@ record_numbers_of_iterations (void)
static unsigned int static unsigned int
execute_vrp (void) execute_vrp (void)
{ {
int i;
edge e;
switch_update *su;
loop_optimizer_init (LOOPS_NORMAL | LOOPS_HAVE_RECORDED_EXITS); loop_optimizer_init (LOOPS_NORMAL | LOOPS_HAVE_RECORDED_EXITS);
rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa); rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa);
scev_initialize (); scev_initialize ();
...@@ -6620,10 +6740,27 @@ execute_vrp (void) ...@@ -6620,10 +6740,27 @@ execute_vrp (void)
ranges are corrected. */ ranges are corrected. */
record_numbers_of_iterations (); record_numbers_of_iterations ();
to_remove_edges = VEC_alloc (edge, heap, 10);
to_update_switch_stmts = VEC_alloc (switch_update, heap, 5);
vrp_initialize (); vrp_initialize ();
ssa_propagate (vrp_visit_stmt, vrp_visit_phi_node); ssa_propagate (vrp_visit_stmt, vrp_visit_phi_node);
vrp_finalize (); vrp_finalize ();
/* Remove dead edges from SWITCH_EXPR optimization. This leaves the
CFG in a broken state and requires a cfg_cleanup run. */
for (i = 0; VEC_iterate (edge, to_remove_edges, i, e); ++i)
remove_edge (e);
/* Update SWITCH_EXPR case label vector. */
for (i = 0; VEC_iterate (switch_update, to_update_switch_stmts, i, su); ++i)
SWITCH_LABELS (su->stmt) = su->vec;
if (VEC_length (edge, to_remove_edges) > 0)
free_dominance_info (CDI_DOMINATORS);
VEC_free (edge, heap, to_remove_edges);
VEC_free (switch_update, heap, to_update_switch_stmts);
/* ASSERT_EXPRs must be removed before finalizing jump threads /* ASSERT_EXPRs must be removed before finalizing jump threads
as finalizing jump threads calls the CFG cleanup code which as finalizing jump threads calls the CFG cleanup code which
does not properly handle ASSERT_EXPRs. */ does not properly handle ASSERT_EXPRs. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment