mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-23 18:01:22 +08:00
Learn CFG cleanup to transform single case switches to gcond.
2017-09-05 Martin Liska <mliska@suse.cz> PR tree-optimization/82032 * tree-cfg.c (generate_range_test): New function. * tree-cfg.h (generate_range_test): Declared here. * tree-cfgcleanup.c (convert_single_case_switch): New function. (cleanup_control_expr_graph): Use it. * tree-switch-conversion.c (try_switch_expansion): Remove assert. (emit_case_nodes): Use generate_range_test. 2017-09-05 Martin Liska <mliska@suse.cz> PR tree-optimization/82032 * g++.dg/other/pr82032.C: New test. * gcc.dg/tree-ssa/pr68198.c: Update scanned pattern. * gcc.dg/tree-ssa/vrp34.c: Likewise. * gcc.dg/switch-10.c: Likewise. From-SVN: r251690
This commit is contained in:
parent
b471c5c6cf
commit
02e637d86f
@ -1,3 +1,14 @@
|
||||
2017-09-05 Martin Liska <mliska@suse.cz>
|
||||
|
||||
PR tree-optimization/82032
|
||||
* tree-cfg.c (generate_range_test): New function.
|
||||
* tree-cfg.h (generate_range_test): Declared here.
|
||||
* tree-cfgcleanup.c (convert_single_case_switch): New function.
|
||||
(cleanup_control_expr_graph): Use it.
|
||||
* tree-switch-conversion.c (try_switch_expansion): Remove
|
||||
assert.
|
||||
(emit_case_nodes): Use generate_range_test.
|
||||
|
||||
2017-09-04 Uros Bizjak <ubizjak@gmail.com>
|
||||
|
||||
PR target/82098
|
||||
|
@ -1,3 +1,11 @@
|
||||
2017-09-05 Martin Liska <mliska@suse.cz>
|
||||
|
||||
PR tree-optimization/82032
|
||||
* g++.dg/other/pr82032.C: New test.
|
||||
* gcc.dg/tree-ssa/pr68198.c: Update scanned pattern.
|
||||
* gcc.dg/tree-ssa/vrp34.c: Likewise.
|
||||
* gcc.dg/switch-10.c: Likewise.
|
||||
|
||||
2017-09-04 Uros Bizjak <ubizjak@gmail.com>
|
||||
|
||||
* gcc.target/i386/mpx/mpx-os-support.h: New file.
|
||||
|
36
gcc/testsuite/g++.dg/other/pr82032.C
Normal file
36
gcc/testsuite/g++.dg/other/pr82032.C
Normal file
@ -0,0 +1,36 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O3 -Wno-return-type" } */
|
||||
|
||||
template <typename a> class b
|
||||
{
|
||||
public:
|
||||
typename a::aa operator[] (typename a::c) { }
|
||||
};
|
||||
class d
|
||||
{
|
||||
public:
|
||||
typedef long c;
|
||||
typedef int aa;
|
||||
};
|
||||
struct e
|
||||
{
|
||||
int af[4];
|
||||
int ag;
|
||||
};
|
||||
b<d> f;
|
||||
bool
|
||||
g (e &i)
|
||||
{
|
||||
for (int h; h; ++h)
|
||||
switch (f[h])
|
||||
{
|
||||
case 'x':
|
||||
case 'a':
|
||||
i.af[h] = 3;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
@ -1,6 +1,4 @@
|
||||
/* { dg-options "-O2 -fdump-tree-cfg" } */
|
||||
/* { dg-final { scan-tree-dump "case 0:" "cfg" } } */
|
||||
/* { dg-final { scan-tree-dump-not "case 1 ... 255:" "cfg" } } */
|
||||
#include <stdint.h>
|
||||
|
||||
void foo (void);
|
||||
@ -20,3 +18,6 @@ test (uint8_t ch)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Switch statement is converted to GIMPLE condition. */
|
||||
/* { dg-final { scan-tree-dump-not "switch" "cfg" } } */
|
||||
|
@ -37,7 +37,5 @@ c_finish_omp_clauses (tree clauses)
|
||||
}
|
||||
}
|
||||
|
||||
/* There are 3 FSM jump threading opportunities, two of which will
|
||||
get filtered out. */
|
||||
/* { dg-final { scan-tree-dump-times "Registering FSM" 1 "thread1"} } */
|
||||
/* { dg-final { scan-tree-dump-times "FSM Thread through multiway branch without threading a multiway branch" 2 "thread1"} } */
|
||||
/* There are 3 FSM jump threading opportunities. */
|
||||
/* { dg-final { scan-tree-dump-times "Registering FSM" 3 "thread1"} } */
|
||||
|
@ -15,5 +15,6 @@ foo (int a)
|
||||
}
|
||||
}
|
||||
|
||||
/* Both ifs should be optimized. */
|
||||
/* { dg-final { scan-tree-dump-times "if \\\(" 0 "vrp1" } } */
|
||||
/* Both ifs should be optimized (and switch statement will be the only if
|
||||
in the function). */
|
||||
/* { dg-final { scan-tree-dump-times "if \\\(" 1 "vrp1" } } */
|
||||
|
@ -8927,7 +8927,31 @@ extract_true_false_controlled_edges (basic_block dom, basic_block phiblock,
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Generate a range test LHS CODE RHS that determines whether INDEX is in the
|
||||
range [low, high]. Place associated stmts before *GSI. */
|
||||
|
||||
void
|
||||
generate_range_test (basic_block bb, tree index, tree low, tree high,
|
||||
tree *lhs, tree *rhs)
|
||||
{
|
||||
tree type = TREE_TYPE (index);
|
||||
tree utype = unsigned_type_for (type);
|
||||
|
||||
low = fold_convert (type, low);
|
||||
high = fold_convert (type, high);
|
||||
|
||||
tree tmp = make_ssa_name (type);
|
||||
gassign *sub1
|
||||
= gimple_build_assign (tmp, MINUS_EXPR, index, low);
|
||||
|
||||
*lhs = make_ssa_name (utype);
|
||||
gassign *a = gimple_build_assign (*lhs, NOP_EXPR, tmp);
|
||||
|
||||
*rhs = fold_build2 (MINUS_EXPR, utype, high, low);
|
||||
gimple_stmt_iterator gsi = gsi_last_bb (bb);
|
||||
gsi_insert_before (&gsi, sub1, GSI_SAME_STMT);
|
||||
gsi_insert_before (&gsi, a, GSI_SAME_STMT);
|
||||
}
|
||||
|
||||
/* Emit return warnings. */
|
||||
|
||||
|
@ -109,6 +109,8 @@ extern basic_block insert_cond_bb (basic_block, gimple *, gimple *,
|
||||
extern bool gimple_find_sub_bbs (gimple_seq, gimple_stmt_iterator *);
|
||||
extern bool extract_true_false_controlled_edges (basic_block, basic_block,
|
||||
edge *, edge *);
|
||||
extern void generate_range_test (basic_block bb, tree index, tree low,
|
||||
tree high, tree *lhs, tree *rhs);
|
||||
|
||||
/* Return true if the LHS of a call should be removed. */
|
||||
|
||||
|
@ -74,6 +74,49 @@ remove_fallthru_edge (vec<edge, va_gc> *ev)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Convert a SWTCH with single non-default case to gcond and replace it
|
||||
at GSI. */
|
||||
|
||||
static bool
|
||||
convert_single_case_switch (gswitch *swtch, gimple_stmt_iterator &gsi)
|
||||
{
|
||||
if (gimple_switch_num_labels (swtch) != 2)
|
||||
return false;
|
||||
|
||||
tree index = gimple_switch_index (swtch);
|
||||
tree default_label = CASE_LABEL (gimple_switch_default_label (swtch));
|
||||
tree label = gimple_switch_label (swtch, 1);
|
||||
tree low = CASE_LOW (label);
|
||||
tree high = CASE_HIGH (label);
|
||||
|
||||
basic_block default_bb = label_to_block_fn (cfun, default_label);
|
||||
basic_block case_bb = label_to_block_fn (cfun, CASE_LABEL (label));
|
||||
|
||||
basic_block bb = gimple_bb (swtch);
|
||||
gcond *cond;
|
||||
|
||||
/* Replace switch statement with condition statement. */
|
||||
if (high)
|
||||
{
|
||||
tree lhs, rhs;
|
||||
generate_range_test (bb, index, low, high, &lhs, &rhs);
|
||||
cond = gimple_build_cond (LE_EXPR, lhs, rhs, NULL_TREE, NULL_TREE);
|
||||
}
|
||||
else
|
||||
cond = gimple_build_cond (EQ_EXPR, index,
|
||||
fold_convert (TREE_TYPE (index), low),
|
||||
NULL_TREE, NULL_TREE);
|
||||
|
||||
gsi_replace (&gsi, cond, true);
|
||||
|
||||
/* Update edges. */
|
||||
edge case_edge = find_edge (bb, case_bb);
|
||||
edge default_edge = find_edge (bb, default_bb);
|
||||
|
||||
case_edge->flags |= EDGE_TRUE_VALUE;
|
||||
default_edge->flags |= EDGE_FALSE_VALUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Disconnect an unreachable block in the control expression starting
|
||||
at block BB. */
|
||||
@ -93,6 +136,12 @@ cleanup_control_expr_graph (basic_block bb, gimple_stmt_iterator gsi,
|
||||
bool warned;
|
||||
tree val = NULL_TREE;
|
||||
|
||||
/* Try to convert a switch with just a single non-default case to
|
||||
GIMPLE condition. */
|
||||
if (gimple_code (stmt) == GIMPLE_SWITCH
|
||||
&& convert_single_case_switch (as_a<gswitch *> (stmt), gsi))
|
||||
stmt = gsi_stmt (gsi);
|
||||
|
||||
fold_defer_overflow_warnings ();
|
||||
switch (gimple_code (stmt))
|
||||
{
|
||||
|
@ -2057,9 +2057,8 @@ try_switch_expansion (gswitch *stmt)
|
||||
expressions being INTEGER_CST. */
|
||||
gcc_assert (TREE_CODE (index_expr) != INTEGER_CST);
|
||||
|
||||
/* Optimization of switch statements with only one label has already
|
||||
occurred, so we should never see them at this point. */
|
||||
gcc_assert (ncases > 1);
|
||||
if (ncases == 1)
|
||||
return false;
|
||||
|
||||
/* Find the default case target label. */
|
||||
tree default_label = CASE_LABEL (gimple_switch_default_label (stmt));
|
||||
@ -2701,27 +2700,13 @@ emit_case_nodes (basic_block bb, tree index, case_node_ptr node,
|
||||
}
|
||||
else if (!low_bound && !high_bound)
|
||||
{
|
||||
tree type = TREE_TYPE (index);
|
||||
tree utype = unsigned_type_for (type);
|
||||
|
||||
tree lhs = make_ssa_name (type);
|
||||
gassign *sub1
|
||||
= gimple_build_assign (lhs, MINUS_EXPR, index, node->low);
|
||||
|
||||
tree converted = make_ssa_name (utype);
|
||||
gassign *a = gimple_build_assign (converted, NOP_EXPR, lhs);
|
||||
|
||||
tree rhs = fold_build2 (MINUS_EXPR, utype,
|
||||
fold_convert (type, node->high),
|
||||
fold_convert (type, node->low));
|
||||
gimple_stmt_iterator gsi = gsi_last_bb (bb);
|
||||
gsi_insert_before (&gsi, sub1, GSI_SAME_STMT);
|
||||
gsi_insert_before (&gsi, a, GSI_SAME_STMT);
|
||||
|
||||
tree lhs, rhs;
|
||||
generate_range_test (bb, index, node->low, node->high,
|
||||
&lhs, &rhs);
|
||||
probability
|
||||
= conditional_probability (default_prob,
|
||||
subtree_prob + default_prob);
|
||||
bb = emit_cmp_and_jump_insns (bb, converted, rhs, GT_EXPR,
|
||||
bb = emit_cmp_and_jump_insns (bb, lhs, rhs, GT_EXPR,
|
||||
default_bb, probability,
|
||||
phi_mapping);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user