The patch covers 2 cases mentioned in the PR.
Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
Ready to be installed?
Thanks,
Martin
gcc/ChangeLog:
PR tree-optimization/94779
* tree-switch-conversion.c (switch_conversion::switch_conversion):
Initialize m_default_unreachable, m_missing_return_in_default
and m_inbound_check_needed.
(switch_conversion::collect): Start with first edge also
if m_default_unreachable or m_missing_return_in_default.
(switch_conversion::check_all_empty_except_final): Ignore
default edge for case where m_default_unreachable is true.
(switch_conversion::phi_leads_to_return): New.
(switch_conversion::build_one_array): Drop boundary
check for linear transformation where
m_missing_return_in_default is true
(switch_conversion::analyze_default_bb): New.
(switch_conversion::gen_inbound_check): Generate if TRUE when
m_default_unreachable or we don't need boundary check.
(switch_conversion::expand): Do transformation as we can't be
sure that the switch will be expanded with JT.
* tree-switch-conversion.h: Declare new functions and
variables.
gcc/testsuite/ChangeLog:
PR tree-optimization/94779
* gcc.dg/tree-ssa/cswtch-6.c: New test.
* gcc.dg/tree-ssa/cswtch-7.c: New test.
---
gcc/testsuite/gcc.dg/tree-ssa/cswtch-6.c | 22 +++++++
gcc/testsuite/gcc.dg/tree-ssa/cswtch-7.c | 19 ++++++
gcc/tree-switch-conversion.c | 78 ++++++++++++++++++++----
gcc/tree-switch-conversion.h | 14 +++++
4 files changed, 122 insertions(+), 11 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/cswtch-6.c
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/cswtch-7.c
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/cswtch-6.c
b/gcc/testsuite/gcc.dg/tree-ssa/cswtch-6.c
new file mode 100644
index 00000000000..e5aa09fdbde
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/cswtch-6.c
@@ -0,0 +1,22 @@
+/* PR tree-optimization/94779 */
+/* { dg-options "-O2 -fdump-tree-switchconv" } */
+/* { dg-do compile { target nonpic } } */
+
+int global;
+
+int f1(unsigned x)
+{
+ int v;
+ switch (x)
+ {
+ case 0:
+ return 1;
+ case 1:
+ return 2;
+ case 2:
+ return 3;
+ }
+}
+
+/* { dg-final { scan-tree-dump-times "Linear transformation with A = 1 and B = 1" 1
"switchconv" } } */
+/* { dg-final { scan-tree-dump-not "if " "switchconv" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/cswtch-7.c
b/gcc/testsuite/gcc.dg/tree-ssa/cswtch-7.c
new file mode 100644
index 00000000000..15ca9849f9d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/cswtch-7.c
@@ -0,0 +1,19 @@
+/* PR tree-optimization/94779 */
+/* { dg-options "-O2 -fdump-tree-switchconv" } */
+/* { dg-do compile { target nonpic } } */
+
+int global;
+
+int f1(unsigned x)
+{
+ switch (x)
+ {
+ case 0:
+ return 1;
+ case 1:
+ return 2;
+ }
+}
+
+/* { dg-final { scan-tree-dump-times "Linear transformation with A = 1 and B = 1" 1
"switchconv" } } */
+/* { dg-final { scan-tree-dump "Switch converted" "switchconv" } } */
diff --git a/gcc/tree-switch-conversion.c b/gcc/tree-switch-conversion.c
index 08dfd6f3580..dd64daf4b92 100644
--- a/gcc/tree-switch-conversion.c
+++ b/gcc/tree-switch-conversion.c
@@ -64,7 +64,9 @@ using namespace tree_switch_conversion;
switch_conversion::switch_conversion (): m_final_bb (NULL),
m_constructors (NULL), m_default_values (NULL),
m_arr_ref_first (NULL), m_arr_ref_last (NULL),
- m_reason (NULL), m_default_case_nonstandard (false), m_cfg_altered (false)
+ m_reason (NULL), m_default_unreachable (false),
+ m_missing_return_in_default (false), m_inbound_check_needed (true),
+ m_default_case_nonstandard (false), m_cfg_altered (false)
{
}
@@ -90,6 +92,8 @@ switch_conversion::collect (gswitch *swtch)
m_default_bb = e_default->dest;
m_default_prob = e_default->probability;
+ analyze_default_bb ();
+
/* Get upper and lower bounds of case values, and the covered range. */
min_case = gimple_switch_label (swtch, 1);
max_case = gimple_switch_label (swtch, branch_num - 1);
@@ -113,7 +117,9 @@ switch_conversion::collect (gswitch *swtch)
last = CASE_HIGH (elt) ? CASE_HIGH (elt) : CASE_LOW (elt);
}
- if (m_contiguous_range)
+ if (m_contiguous_range
+ || m_default_unreachable
+ || m_missing_return_in_default)
e_first = gimple_switch_edge (cfun, swtch, 1);
else
e_first = e_default;
@@ -142,7 +148,7 @@ switch_conversion::collect (gswitch *swtch)
&& single_succ (e->dest) == m_final_bb)
continue;
- if (e == e_default && m_contiguous_range)
+ if (e == e_default && (m_contiguous_range || m_default_unreachable))
{
m_default_case_nonstandard = true;
continue;
@@ -211,6 +217,9 @@ switch_conversion::check_all_empty_except_final ()
if (e->dest == m_final_bb)
continue;
+ if (e == e_default && m_default_unreachable)
+ continue;
+
if (!empty_block_p (e->dest))
{
if (m_contiguous_range && e == e_default)
@@ -572,6 +581,24 @@ switch_conversion::array_value_type (tree type, int num)
return smaller_type;
}
+/* Return true if PHI leads only to a return statement. */
+
+bool
+switch_conversion::phi_leads_to_return (gphi *phi)
+{
+ use_operand_p use_p;
+ imm_use_iterator iterator;
+
+ FOR_EACH_IMM_USE_FAST (use_p, iterator, PHI_RESULT (phi))
+ {
+ gimple *stmt = USE_STMT (use_p);
+ if (!is_a<greturn *> (stmt) && !is_gimple_debug (stmt))
+ return false;
+ }
+
+ return true;
+}
+
/* Create an appropriate array type and declaration and assemble a static
array variable. Also create a load statement that initializes
the variable in question with a value from the static array. SWTCH is
@@ -609,6 +636,10 @@ switch_conversion::build_one_array (int num, tree
arr_index_type,
" and B = %" PRId64 "\n", coeff_a.to_shwi (),
coeff_b.to_shwi ());
+ if (m_phi_count == 1 && phi_leads_to_return (phi)
+ && m_missing_return_in_default)
+ m_inbound_check_needed = false;
+
/* We must use type of constructor values. */
gimple_seq seq = NULL;
tree tmp = gimple_convert (&seq, type, m_index_expr);
@@ -807,6 +838,34 @@ switch_conversion::fix_phi_nodes (edge e1f, edge e2f,
basic_block bbf)
}
}
+/* Analyze default BB. */
+
+void
+switch_conversion::analyze_default_bb ()
+{
+ gimple_seq stmts = bb_seq (m_default_bb);
+ if (gimple_seq_unreachable_p (stmts))
+ m_default_unreachable = true;
+
+ gimple_stmt_iterator gsi = gsi_last (stmts);
+ greturn *ret = dyn_cast<greturn *> (gsi_stmt (gsi));
+ if (ret == NULL
+ || gimple_return_retval (ret) != NULL_TREE
+ || VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))))
+ return;
+
+ for (gsi_prev (&gsi); !gsi_end_p (gsi); gsi_prev (&gsi))
+ {
+ gimple *stmt = gsi_stmt (gsi);
+ if (gimple_code (stmt) != GIMPLE_LABEL
+ && !is_gimple_debug (stmt)
+ && !gimple_clobber_p (stmt))
+ return;
+ }
+
+ m_missing_return_in_default = true;
+}
+
/* Creates a check whether the switch expression value actually falls into the
range given by all the cases. If it does not, the temporaries are loaded
with default values instead. */
@@ -841,7 +900,11 @@ switch_conversion::gen_inbound_check ()
gsi_next (&gsi);
bound = fold_convert_loc (loc, utype, m_range_size);
- cond_stmt = gimple_build_cond (LE_EXPR, tidx, bound, NULL_TREE, NULL_TREE);
+ if (m_default_unreachable || !m_inbound_check_needed)
+ cond_stmt = gimple_build_cond (EQ_EXPR, integer_one_node, integer_one_node,
+ NULL_TREE, NULL_TREE);
+ else
+ cond_stmt = gimple_build_cond (LE_EXPR, tidx, bound, NULL_TREE, NULL_TREE);
gsi_insert_before (&gsi, cond_stmt, GSI_SAME_STMT);
update_stmt (cond_stmt);
@@ -993,13 +1056,6 @@ switch_conversion::expand (gswitch *swtch)
return;
}
- if (m_uniq <= 2)
- {
- /* This will be expanded as a decision tree . */
- m_reason = "expanding as jumps is preferable";
- return;
- }
-
/* If there is no common successor, we cannot do the transformation. */
if (!m_final_bb)
{
diff --git a/gcc/tree-switch-conversion.h b/gcc/tree-switch-conversion.h
index 62cfde168c8..5a380dd1ffb 100644
--- a/gcc/tree-switch-conversion.h
+++ b/gcc/tree-switch-conversion.h
@@ -800,6 +800,12 @@ public:
bbf description in the comment below). */
void fix_phi_nodes (edge e1f, edge e2f, basic_block bbf);
+ /* Analyze default BB. */
+ void analyze_default_bb ();
+
+ /* Return true if PHI leads only to a return statement. */
+ bool phi_leads_to_return (gphi *phi);
+
/* Creates a check whether the switch expression value actually falls into
the
range given by all the cases. If it does not, the temporaries are loaded
with default values instead. */
@@ -869,6 +875,14 @@ public:
range_max inclusive. */
bool m_contiguous_range;
+ /* True if default case is unreachable. */
+ bool m_default_unreachable;
+
+ /* True if default BB misses return statement for non-void functions. */
+ bool m_missing_return_in_default;
+
+ bool m_inbound_check_needed;
+
/* True if default case does not have the required shape for other case
labels. */
bool m_default_case_nonstandard;
--
2.29.2