On Mon, 3 Sep 2012, Richard Guenther wrote:
You do work above and then bail late here. Always do early exists early
to reduce useless compile-time.
[...]
You need to verify that fold_ternary returns something that is valid GIMPLE.
fold () in general happily returns trees that are in the need of
re-gimplification.
You expect a CONSTRUCTOR or VECTOR_CST here, so you should check
for that.
Hello,
here is a new version of the patch, again tested on x86_64-linux-gnu.
2012-09-08 Marc Glisse <marc.gli...@inria.fr>
gcc/
* tree-ssa-forwprop.c (simplify_permutation): Handle CONSTRUCTOR.
gcc/testsuite/
* gcc.dg/tree-ssa/forwprop-20.c: New testcase.
--
Marc Glisse
Index: gcc/testsuite/gcc.dg/tree-ssa/forwprop-20.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/forwprop-20.c (revision 0)
+++ gcc/testsuite/gcc.dg/tree-ssa/forwprop-20.c (revision 0)
@@ -0,0 +1,70 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target double64 } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+#include <stdint.h>
+
+/* All of these optimizations happen for unsupported vector modes as a
+ consequence of the lowering pass. We need to test with a vector mode
+ that is supported by default on at least some architectures, or make
+ the test target specific so we can pass a flag like -mavx. */
+
+typedef double vecf __attribute__ ((vector_size (2 * sizeof (double))));
+typedef int64_t veci __attribute__ ((vector_size (2 * sizeof (int64_t))));
+
+void f (double d, vecf* r)
+{
+ vecf x = { -d, 5 };
+ vecf y = { 1, 4 };
+ veci m = { 2, 0 };
+ *r = __builtin_shuffle (x, y, m); // { 1, -d }
+}
+
+void g (float d, vecf* r)
+{
+ vecf x = { d, 5 };
+ vecf y = { 1, 4 };
+ veci m = { 2, 1 };
+ *r = __builtin_shuffle (x, y, m); // { 1, 5 }
+}
+
+void h (double d, vecf* r)
+{
+ vecf x = { d + 1, 5 };
+ vecf y = { 1 , 4 };
+ veci m = { 2 , 0 };
+ *r = __builtin_shuffle (y, x, m); // { d + 1, 1 }
+}
+
+void i (float d, vecf* r)
+{
+ vecf x = { d, 5 };
+ veci m = { 1, 0 };
+ *r = __builtin_shuffle (x, m); // { 5, d }
+}
+
+void j (vecf* r)
+{
+ vecf y = { 1, 2 };
+ veci m = { 0, 0 };
+ *r = __builtin_shuffle (y, m); // { 1, 1 }
+}
+
+void k (vecf* r)
+{
+ vecf x = { 3, 4 };
+ vecf y = { 1, 2 };
+ veci m = { 3, 0 };
+ *r = __builtin_shuffle (x, y, m); // { 2, 3 }
+}
+
+void l (double d, vecf* r)
+{
+ vecf x = { -d, 5 };
+ vecf y = { d, 4 };
+ veci m = { 2, 0 };
+ *r = __builtin_shuffle (x, y, m); // { d, -d }
+}
+
+/* { dg-final { scan-tree-dump-not "VEC_PERM_EXPR" "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
Property changes on: gcc/testsuite/gcc.dg/tree-ssa/forwprop-20.c
___________________________________________________________________
Added: svn:eol-style
+ native
Added: svn:keywords
+ Author Date Id Revision URL
Index: gcc/tree-ssa-forwprop.c
===================================================================
--- gcc/tree-ssa-forwprop.c (revision 191082)
+++ gcc/tree-ssa-forwprop.c (working copy)
@@ -2599,75 +2599,134 @@ is_combined_permutation_identity (tree m
if (j == i)
maybe_identity2 = false;
else if (j == i + nelts)
maybe_identity1 = false;
else
return 0;
}
return maybe_identity1 ? 1 : maybe_identity2 ? 2 : 0;
}
-/* Combine two shuffles in a row. Returns 1 if there were any changes
- made, 2 if cfg-cleanup needs to run. Else it returns 0. */
+/* Combine a shuffle with its arguments. Returns 1 if there were any
+ changes made, 2 if cfg-cleanup needs to run. Else it returns 0. */
static int
simplify_permutation (gimple_stmt_iterator *gsi)
{
gimple stmt = gsi_stmt (*gsi);
gimple def_stmt;
- tree op0, op1, op2, op3;
- enum tree_code code = gimple_assign_rhs_code (stmt);
- enum tree_code code2;
+ tree op0, op1, op2, op3, arg0, arg1;
+ enum tree_code code;
- gcc_checking_assert (code == VEC_PERM_EXPR);
+ gcc_checking_assert (gimple_assign_rhs_code (stmt) == VEC_PERM_EXPR);
op0 = gimple_assign_rhs1 (stmt);
op1 = gimple_assign_rhs2 (stmt);
op2 = gimple_assign_rhs3 (stmt);
- if (TREE_CODE (op0) != SSA_NAME)
- return 0;
-
if (TREE_CODE (op2) != VECTOR_CST)
return 0;
- if (op0 != op1)
- return 0;
+ if (TREE_CODE (op0) == VECTOR_CST)
+ {
+ code = VECTOR_CST;
+ arg0 = op0;
+ }
+ else if (TREE_CODE (op0) == SSA_NAME)
+ {
+ def_stmt = SSA_NAME_DEF_STMT (op0);
+ if (!def_stmt || !is_gimple_assign (def_stmt)
+ || !can_propagate_from (def_stmt))
+ return 0;
- def_stmt = SSA_NAME_DEF_STMT (op0);
- if (!def_stmt || !is_gimple_assign (def_stmt)
- || !can_propagate_from (def_stmt))
+ code = gimple_assign_rhs_code (def_stmt);
+ arg0 = gimple_assign_rhs1 (def_stmt);
+ }
+ else
return 0;
- code2 = gimple_assign_rhs_code (def_stmt);
-
/* Two consecutive shuffles. */
- if (code2 == VEC_PERM_EXPR)
+ if (code == VEC_PERM_EXPR)
{
tree orig;
int ident;
+
+ if (op0 != op1)
+ return 0;
op3 = gimple_assign_rhs3 (def_stmt);
if (TREE_CODE (op3) != VECTOR_CST)
return 0;
ident = is_combined_permutation_identity (op3, op2);
if (!ident)
return 0;
orig = (ident == 1) ? gimple_assign_rhs1 (def_stmt)
: gimple_assign_rhs2 (def_stmt);
gimple_assign_set_rhs1 (stmt, unshare_expr (orig));
gimple_assign_set_rhs_code (stmt, TREE_CODE (orig));
gimple_set_num_ops (stmt, 2);
update_stmt (stmt);
return remove_prop_source_from_use (op0) ? 2 : 1;
}
- return false;
+ /* Shuffle of a constructor. */
+ else if (code == CONSTRUCTOR || code == VECTOR_CST)
+ {
+ tree opt;
+ bool ret = false;
+ if (op0 != op1)
+ {
+ if (TREE_CODE (op0) == SSA_NAME && !has_single_use (op0))
+ return 0;
+
+ if (TREE_CODE (op1) == VECTOR_CST)
+ arg1 = op1;
+ else if (TREE_CODE (op1) == SSA_NAME)
+ {
+ enum tree_code code2;
+
+ if (!has_single_use (op1))
+ return 0;
+
+ gimple def_stmt2 = SSA_NAME_DEF_STMT (op1);
+ if (!def_stmt2 || !is_gimple_assign (def_stmt2)
+ || !can_propagate_from (def_stmt2))
+ return 0;
+
+ code2 = gimple_assign_rhs_code (def_stmt2);
+ if (code2 != CONSTRUCTOR && code2 != VECTOR_CST)
+ return 0;
+ arg1 = gimple_assign_rhs1 (def_stmt2);
+ }
+ else
+ return 0;
+ }
+ else
+ {
+ /* Already used twice in this statement. */
+ if (TREE_CODE (op0) == SSA_NAME && num_imm_uses (op0) > 2)
+ return 0;
+ arg1 = arg0;
+ }
+ opt = fold_ternary (VEC_PERM_EXPR, TREE_TYPE(op0), arg0, arg1, op2);
+ if (!opt
+ || (TREE_CODE (opt) != CONSTRUCTOR && TREE_CODE(opt) != VECTOR_CST))
+ return 0;
+ gimple_assign_set_rhs_from_tree (gsi, opt);
+ update_stmt (gsi_stmt (*gsi));
+ if (TREE_CODE (op0) == SSA_NAME)
+ ret = remove_prop_source_from_use (op0);
+ if (op0 != op1 && TREE_CODE (op1) == SSA_NAME)
+ ret |= remove_prop_source_from_use (op1);
+ return ret ? 2 : 1;
+ }
+
+ return 0;
}
/* Main entry point for the forward propagation and statement combine
optimizer. */
static unsigned int
ssa_forward_propagate_and_combine (void)
{
basic_block bb;
unsigned int todoflags = 0;