middle-end/105715 - missed RTL if-conversion with COND_EXPR expansion
Checks
Commit Message
When the COND_EXPR condition operand was split out to a separate stmt
it became subject to CSE with other condition evaluations. This
unfortunately leads to TER no longer applying and in turn RTL
expansion of COND_EXPRs no longer seeing the condition and thus
failing to try conditional move expansion. This can be seen with
gcc.target/i386/pr45685.c when built with -march=cascadelake which
then FAILs to produce the expected number of cmovs.
It can also be seen when we create more COND_EXPRs early like for
instruction selection of MIN/MAX operations that map to IEEE
a > b ? a : b expression semantics.
Bootstrapped and tested on x86_64-unknown-linux-gnu.
I'll push this after confirming it fixes all the fallout of
early MIN/MAX if conversion.
PR middle-end/105715
* gimple-isel.cc (gimple_expand_vec_exprs): Merge into...
(pass_gimple_isel::execute): ... this. Duplicate
comparison defs of COND_EXPRs.
---
gcc/gimple-isel.cc | 121 ++++++++++++++++++++++++++++++---------------
1 file changed, 80 insertions(+), 41 deletions(-)
@@ -336,11 +336,43 @@ gimple_expand_vec_cond_expr (struct function *fun, gimple_stmt_iterator *gsi,
-/* Iterate all gimple statements and try to expand
- VEC_COND_EXPR assignments. */
+namespace {
+
+const pass_data pass_data_gimple_isel =
+{
+ GIMPLE_PASS, /* type */
+ "isel", /* name */
+ OPTGROUP_VEC, /* optinfo_flags */
+ TV_NONE, /* tv_id */
+ PROP_cfg, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_update_ssa, /* todo_flags_finish */
+};
-static unsigned int
-gimple_expand_vec_exprs (struct function *fun)
+class pass_gimple_isel : public gimple_opt_pass
+{
+public:
+ pass_gimple_isel (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_gimple_isel, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ bool gate (function *) final override
+ {
+ return true;
+ }
+
+ unsigned int execute (function *fun) final override;
+}; // class pass_gimple_isel
+
+
+/* Iterate all gimple statements and perform pre RTL expansion
+ GIMPLE massaging to improve instruction selection. */
+
+unsigned int
+pass_gimple_isel::execute (struct function *fun)
{
gimple_stmt_iterator gsi;
basic_block bb;
@@ -352,6 +384,8 @@ gimple_expand_vec_exprs (struct function *fun)
{
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
+ /* Pre-expand VEC_COND_EXPRs to .VCOND* internal function
+ calls mapping to supported optabs. */
gimple *g = gimple_expand_vec_cond_expr (fun, &gsi,
&vec_cond_ssa_name_uses);
if (g != NULL)
@@ -361,14 +395,54 @@ gimple_expand_vec_exprs (struct function *fun)
gsi_replace (&gsi, g, false);
}
+ /* Recognize .VEC_SET and .VEC_EXTRACT patterns. */
cfg_changed |= gimple_expand_vec_set_extract_expr (fun, &gsi);
-
if (gsi_end_p (gsi))
break;
+
+ gassign *stmt = dyn_cast <gassign *> (*gsi);
+ if (!stmt)
+ continue;
+
+ tree_code code = gimple_assign_rhs_code (stmt);
+ tree lhs = gimple_assign_lhs (stmt);
+ if (TREE_CODE_CLASS (code) == tcc_comparison
+ && !has_single_use (lhs))
+ {
+ /* Duplicate COND_EXPR condition defs when they are
+ comparisons so RTL expansion with the help of TER
+ can perform better if conversion. */
+ imm_use_iterator imm_iter;
+ use_operand_p use_p;
+ auto_vec<gassign *, 4> cond_exprs;
+ unsigned cnt = 0;
+ FOR_EACH_IMM_USE_FAST (use_p, imm_iter, lhs)
+ {
+ if (is_gimple_debug (USE_STMT (use_p)))
+ continue;
+ cnt++;
+ if (gimple_bb (USE_STMT (use_p)) == bb
+ && is_gimple_assign (USE_STMT (use_p))
+ && gimple_assign_rhs1_ptr (USE_STMT (use_p)) == use_p->use
+ && gimple_assign_rhs_code (USE_STMT (use_p)) == COND_EXPR)
+ cond_exprs.safe_push (as_a <gassign *> (USE_STMT (use_p)));
+ }
+ for (unsigned i = cond_exprs.length () == cnt ? 1 : 0;
+ i < cond_exprs.length (); ++i)
+ {
+ gassign *copy = as_a <gassign *> (gimple_copy (stmt));
+ tree new_def = duplicate_ssa_name (lhs, copy);
+ gimple_assign_set_lhs (copy, new_def);
+ auto gsi2 = gsi_for_stmt (cond_exprs[i]);
+ gsi_insert_before (&gsi2, copy, GSI_SAME_STMT);
+ gimple_assign_set_rhs1 (cond_exprs[i], new_def);
+ update_stmt (cond_exprs[i]);
+ }
+ }
}
}
- for (hash_map<tree, unsigned int>::iterator it = vec_cond_ssa_name_uses.begin ();
+ for (auto it = vec_cond_ssa_name_uses.begin ();
it != vec_cond_ssa_name_uses.end (); ++it)
bitmap_set_bit (dce_ssa_names, SSA_NAME_VERSION ((*it).first));
@@ -377,41 +451,6 @@ gimple_expand_vec_exprs (struct function *fun)
return cfg_changed ? TODO_cleanup_cfg : 0;
}
-namespace {
-
-const pass_data pass_data_gimple_isel =
-{
- GIMPLE_PASS, /* type */
- "isel", /* name */
- OPTGROUP_VEC, /* optinfo_flags */
- TV_NONE, /* tv_id */
- PROP_cfg, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_update_ssa, /* todo_flags_finish */
-};
-
-class pass_gimple_isel : public gimple_opt_pass
-{
-public:
- pass_gimple_isel (gcc::context *ctxt)
- : gimple_opt_pass (pass_data_gimple_isel, ctxt)
- {}
-
- /* opt_pass methods: */
- bool gate (function *) final override
- {
- return true;
- }
-
- unsigned int execute (function *fun) final override
- {
- return gimple_expand_vec_exprs (fun);
- }
-
-}; // class pass_gimple_isel
-
} // anon namespace
gimple_opt_pass *