Skip to content

Instantly share code, notes, and snippets.

@marxin
Created September 23, 2019 13:06
Show Gist options
  • Save marxin/7a8592aa6b9104d17bf4fb604e948e33 to your computer and use it in GitHub Desktop.
Save marxin/7a8592aa6b9104d17bf4fb604e948e33 to your computer and use it in GitHub Desktop.
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 5a93447f520..f06ce5fb912 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -3793,6 +3793,9 @@ expand_gimple_stmt_1 (gimple *stmt)
ops.type = TREE_TYPE (lhs);
switch (get_gimple_rhs_class (ops.code))
{
+ case GIMPLE_QUATERNARY_RHS:
+ ops.op3 = gimple_assign_rhs4 (assign_stmt);
+ /* Fallthru */
case GIMPLE_TERNARY_RHS:
ops.op2 = gimple_assign_rhs3 (assign_stmt);
/* Fallthru */
diff --git a/gcc/expr.c b/gcc/expr.c
index 2f2b53f8b69..45e170c6b5e 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -8450,7 +8450,7 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode,
int ignore;
bool reduce_bit_field;
location_t loc = ops->location;
- tree treeop0, treeop1, treeop2;
+ tree treeop0, treeop1, treeop2, treeop3;
#define REDUCE_BIT_FIELD(expr) (reduce_bit_field \
? reduce_to_bit_field_precision ((expr), \
target, \
@@ -8464,13 +8464,15 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode,
treeop0 = ops->op0;
treeop1 = ops->op1;
treeop2 = ops->op2;
+ treeop3 = ops->op3;
/* We should be called only on simple (binary or unary) expressions,
exactly those that are valid in gimple expressions that aren't
GIMPLE_SINGLE_RHS (or invalid). */
gcc_assert (get_gimple_rhs_class (code) == GIMPLE_UNARY_RHS
|| get_gimple_rhs_class (code) == GIMPLE_BINARY_RHS
- || get_gimple_rhs_class (code) == GIMPLE_TERNARY_RHS);
+ || get_gimple_rhs_class (code) == GIMPLE_TERNARY_RHS
+ || get_gimple_rhs_class (code) == GIMPLE_QUATERNARY_RHS);
ignore = (target == const0_rtx
|| ((CONVERT_EXPR_CODE_P (code)
@@ -9141,16 +9143,15 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode,
if (temp != 0)
return temp;
- /* For vector MIN <x, y>, expand it a VEC_COND_EXPR <x <= y, x, y>
+ /* For vector MIN <x, y>, expand it a VEC_COND_*_EXPR <x <= y, x, y>
and similarly for MAX <x, y>. */
if (VECTOR_TYPE_P (type))
{
tree t0 = make_tree (type, op0);
tree t1 = make_tree (type, op1);
- tree comparison = build2 (code == MIN_EXPR ? LE_EXPR : GE_EXPR,
- type, t0, t1);
- return expand_vec_cond_expr (type, comparison, t0, t1,
- original_target);
+ return expand_vec_cond_expr (type,
+ code == MIN_EXPR ? LE_EXPR : GE_EXPR,
+ t0, t1, t0, t1, original_target);
}
/* At this point, a MEM target is no longer useful; we will get better
@@ -9743,8 +9744,9 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode,
return temp;
}
- case VEC_COND_EXPR:
- target = expand_vec_cond_expr (type, treeop0, treeop1, treeop2, target);
+ CASE_VEC_COND_EXPR:
+ target = expand_vec_cond_expr (type, code, treeop0, treeop1, treeop2,
+ treeop3, target);
return target;
case VEC_DUPLICATE_EXPR:
@@ -9971,6 +9973,9 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
ops.code = gimple_assign_rhs_code (g);
switch (get_gimple_rhs_class (ops.code))
{
+ case GIMPLE_QUATERNARY_RHS:
+ ops.op3 = gimple_assign_rhs4 (g);
+ /* Fallthru */
case GIMPLE_TERNARY_RHS:
ops.op2 = gimple_assign_rhs3 (g);
/* Fallthru */
@@ -11774,6 +11779,7 @@ maybe_optimize_pow2p_mod_cmp (enum tree_code code, tree *arg0, tree *arg1)
ops.op0 = treeop0;
ops.op1 = treeop1;
ops.op2 = NULL_TREE;
+ ops.op3 = NULL_TREE;
start_sequence ();
rtx mor = expand_expr_real_2 (&ops, NULL_RTX, TYPE_MODE (ops.type),
EXPAND_NORMAL);
@@ -11790,6 +11796,7 @@ maybe_optimize_pow2p_mod_cmp (enum tree_code code, tree *arg0, tree *arg1)
ops.op0 = treeop0;
ops.op1 = c3;
ops.op2 = NULL_TREE;
+ ops.op3 = NULL_TREE;
start_sequence ();
rtx mur = expand_expr_real_2 (&ops, NULL_RTX, TYPE_MODE (ops.type),
EXPAND_NORMAL);
@@ -11977,6 +11984,7 @@ maybe_optimize_mod_cmp (enum tree_code code, tree *arg0, tree *arg1)
ops.op0 = treeop0;
ops.op1 = treeop1;
ops.op2 = NULL_TREE;
+ ops.op3 = NULL_TREE;
start_sequence ();
rtx mor = expand_expr_real_2 (&ops, NULL_RTX, TYPE_MODE (ops.type),
EXPAND_NORMAL);
@@ -12082,16 +12090,18 @@ do_store_flag (sepops ops, rtx target, machine_mode mode)
expander for this. */
if (TREE_CODE (ops->type) == VECTOR_TYPE)
{
- tree ifexp = build2 (ops->code, ops->type, arg0, arg1);
if (VECTOR_BOOLEAN_TYPE_P (ops->type)
&& expand_vec_cmp_expr_p (TREE_TYPE (arg0), ops->type, ops->code))
- return expand_vec_cmp_expr (ops->type, ifexp, target);
+ {
+ tree ifexp = build2 (ops->code, ops->type, arg0, arg1);
+ return expand_vec_cmp_expr (ops->type, ifexp, target);
+ }
else
{
tree if_true = constant_boolean_node (true, ops->type);
tree if_false = constant_boolean_node (false, ops->type);
- return expand_vec_cond_expr (ops->type, ifexp, if_true,
- if_false, target);
+ return expand_vec_cond_expr (ops->type, ops->code, arg0, arg1,
+ if_true, if_false, target);
}
}
diff --git a/gcc/expr.h b/gcc/expr.h
index 6eb70bf12f1..312d25c7be4 100644
--- a/gcc/expr.h
+++ b/gcc/expr.h
@@ -51,7 +51,7 @@ typedef struct separate_ops
enum tree_code code;
location_t location;
tree type;
- tree op0, op1, op2;
+ tree op0, op1, op2, op3;
} *sepops;
/* This is run during target initialization to set up which modes can be
diff --git a/gcc/gimple-expr.c b/gcc/gimple-expr.c
index b0c9f9b671a..435ee4ca5cd 100644
--- a/gcc/gimple-expr.c
+++ b/gcc/gimple-expr.c
@@ -526,36 +526,47 @@ create_tmp_reg_fn (struct function *fn, tree type, const char *prefix)
void
extract_ops_from_tree (tree expr, enum tree_code *subcode_p, tree *op1_p,
- tree *op2_p, tree *op3_p)
+ tree *op2_p, tree *op3_p, tree *op4_p)
{
enum gimple_rhs_class grhs_class;
*subcode_p = TREE_CODE (expr);
grhs_class = get_gimple_rhs_class (*subcode_p);
- if (grhs_class == GIMPLE_TERNARY_RHS)
+ if (grhs_class == GIMPLE_QUATERNARY_RHS)
{
*op1_p = TREE_OPERAND (expr, 0);
*op2_p = TREE_OPERAND (expr, 1);
*op3_p = TREE_OPERAND (expr, 2);
+ *op4_p = TREE_OPERAND (expr, 3);
+ }
+ else if (grhs_class == GIMPLE_TERNARY_RHS)
+ {
+ *op1_p = TREE_OPERAND (expr, 0);
+ *op2_p = TREE_OPERAND (expr, 1);
+ *op3_p = TREE_OPERAND (expr, 2);
+ *op4_p = NULL_TREE;
}
else if (grhs_class == GIMPLE_BINARY_RHS)
{
*op1_p = TREE_OPERAND (expr, 0);
*op2_p = TREE_OPERAND (expr, 1);
*op3_p = NULL_TREE;
+ *op4_p = NULL_TREE;
}
else if (grhs_class == GIMPLE_UNARY_RHS)
{
*op1_p = TREE_OPERAND (expr, 0);
*op2_p = NULL_TREE;
*op3_p = NULL_TREE;
+ *op4_p = NULL_TREE;
}
else if (grhs_class == GIMPLE_SINGLE_RHS)
{
*op1_p = expr;
*op2_p = NULL_TREE;
*op3_p = NULL_TREE;
+ *op4_p = NULL_TREE;
}
else
gcc_unreachable ();
diff --git a/gcc/gimple-expr.h b/gcc/gimple-expr.h
index 1ad1432bd17..c37bff201cc 100644
--- a/gcc/gimple-expr.h
+++ b/gcc/gimple-expr.h
@@ -36,7 +36,7 @@ extern tree create_tmp_reg_fn (struct function *, tree, const char *);
extern void extract_ops_from_tree (tree, enum tree_code *, tree *, tree *,
- tree *);
+ tree *, tree *);
extern void gimple_cond_get_ops_from_tree (tree, enum tree_code *, tree *,
tree *);
extern bool is_gimple_lvalue (tree);
@@ -151,8 +151,8 @@ static inline void
extract_ops_from_tree (tree expr, enum tree_code *code, tree *op0,
tree *op1)
{
- tree op2;
- extract_ops_from_tree (expr, code, op0, op1, &op2);
+ tree op2, op3;
+ extract_ops_from_tree (expr, code, op0, op1, &op2, &op3);
gcc_assert (op2 == NULL_TREE);
}
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index 8d642de2f67..6d1abdf1f36 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -470,6 +470,10 @@ fold_gimple_assign (gimple_stmt_iterator *si)
}
break;
+ case GIMPLE_QUATERNARY_RHS:
+ // TODO
+ break;
+
case GIMPLE_INVALID_RHS:
gcc_unreachable ();
}
@@ -4676,7 +4680,8 @@ replace_stmt_with_simplification (gimple_stmt_iterator *gsi,
gimple_assign_set_rhs_with_ops (gsi, res_op->code,
res_op->op_or_null (0),
res_op->op_or_null (1),
- res_op->op_or_null (2));
+ res_op->op_or_null (2),
+ res_op->op_or_null (3));
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "gimple_simplified to ");
@@ -6361,6 +6366,10 @@ gimple_fold_stmt_to_constant_1 (gimple *stmt, tree (*valueize) (tree),
gimple_expr_type (stmt), op0, op1, op2);
}
+ case GIMPLE_QUATERNARY_RHS:
+ // TODO
+ return NULL_TREE;
+
default:
gcc_unreachable ();
}
@@ -7628,6 +7637,7 @@ gimple_assign_nonnegative_warnv_p (gimple *stmt, bool *strict_overflow_p,
gimple_assign_rhs2 (stmt),
strict_overflow_p, depth);
case GIMPLE_TERNARY_RHS:
+ case GIMPLE_QUATERNARY_RHS:
return false;
case GIMPLE_SINGLE_RHS:
return tree_single_nonnegative_warnv_p (gimple_assign_rhs1 (stmt),
@@ -7722,6 +7732,7 @@ gimple_assign_integer_valued_real_p (gimple *stmt, int depth)
gimple_assign_rhs1 (stmt),
gimple_assign_rhs2 (stmt), depth);
case GIMPLE_TERNARY_RHS:
+ case GIMPLE_QUATERNARY_RHS:
return false;
case GIMPLE_SINGLE_RHS:
return integer_valued_real_single_p (gimple_assign_rhs1 (stmt), depth);
diff --git a/gcc/gimple-match-head.c b/gcc/gimple-match-head.c
index 53278168a59..ebe60ba774d 100644
--- a/gcc/gimple-match-head.c
+++ b/gcc/gimple-match-head.c
@@ -974,6 +974,9 @@ gimple_simplify (gimple *stmt, gimple_match_op *res_op, gimple_seq *seq,
return (gimple_resimplify3 (seq, res_op, valueize)
|| valueized);
}
+ case GIMPLE_QUATERNARY_RHS:
+ // TODO: add support
+ break;
default:
gcc_unreachable ();
}
diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index 2d5ece06805..d77e647282b 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -620,6 +620,59 @@ dump_ternary_rhs (pretty_printer *buffer, gassign *gs, int spc,
}
}
+static void
+dump_comparison (pretty_printer *buffer, tree_code code)
+{
+ switch (code)
+ {
+ case LT_EXPR:
+ pp_less (buffer);
+ break;
+ case GT_EXPR:
+ pp_greater (buffer);
+ break;
+ case LE_EXPR:
+ pp_less_equal (buffer);
+ break;
+ case GE_EXPR:
+ pp_greater_equal (buffer);
+ break;
+ case EQ_EXPR:
+ pp_string (buffer, "==");
+ break;
+ case NE_EXPR:
+ pp_string (buffer, "!=");
+ break;
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Helper for dump_gimple_assign. Print the quaternary RHS of the
+ assignment GS. BUFFER, SPC and FLAGS are as in pp_gimple_stmt_1. */
+
+static void
+dump_quaternary_rhs (pretty_printer *buffer, gassign *gs, int spc,
+ dump_flags_t flags)
+{
+ enum tree_code code = gimple_assign_rhs_code (gs);
+ switch (code)
+ {
+ CASE_VEC_COND_EXPR:
+ dump_generic_node (buffer, gimple_assign_rhs1 (gs), spc, flags, false);
+ pp_space (buffer);
+ dump_comparison (buffer, vec_cmp_to_cmp_code (code));
+ pp_space (buffer);
+ dump_generic_node (buffer, gimple_assign_rhs2 (gs), spc, flags, false);
+ pp_string (buffer, " ? ");
+ dump_generic_node (buffer, gimple_assign_rhs3 (gs), spc, flags, false);
+ pp_string (buffer, " : ");
+ dump_generic_node (buffer, gimple_assign_rhs4 (gs), spc, flags, false);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+}
/* Dump the gimple assignment GS. BUFFER, SPC and FLAGS are as in
pp_gimple_stmt_1. */
@@ -675,6 +728,8 @@ dump_gimple_assign (pretty_printer *buffer, gassign *gs, int spc,
dump_binary_rhs (buffer, gs, spc, flags);
else if (gimple_num_ops (gs) == 4)
dump_ternary_rhs (buffer, gs, spc, flags);
+ else if (gimple_num_ops (gs) == 5)
+ dump_quaternary_rhs (buffer, gs, spc, flags);
else
gcc_unreachable ();
if (!(flags & TDF_RHS_ONLY))
@@ -1518,26 +1573,7 @@ dump_gimple_omp_for (pretty_printer *buffer, gomp_for *gs, int spc,
dump_generic_node (buffer, gimple_omp_for_index (gs, i), spc,
flags, false);
pp_space (buffer);
- switch (gimple_omp_for_cond (gs, i))
- {
- case LT_EXPR:
- pp_less (buffer);
- break;
- case GT_EXPR:
- pp_greater (buffer);
- break;
- case LE_EXPR:
- pp_less_equal (buffer);
- break;
- case GE_EXPR:
- pp_greater_equal (buffer);
- break;
- case NE_EXPR:
- pp_string (buffer, "!=");
- break;
- default:
- gcc_unreachable ();
- }
+ dump_comparison (buffer, gimple_omp_for_cond (gs, i));
pp_space (buffer);
dump_generic_node (buffer, gimple_omp_for_final (gs, i), spc,
flags, false);
diff --git a/gcc/gimple.c b/gcc/gimple.c
index 88250cad16b..876bb7ce571 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -424,10 +424,10 @@ gassign *
gimple_build_assign (tree lhs, tree rhs MEM_STAT_DECL)
{
enum tree_code subcode;
- tree op1, op2, op3;
+ tree op1, op2, op3, op4;
- extract_ops_from_tree (rhs, &subcode, &op1, &op2, &op3);
- return gimple_build_assign (lhs, subcode, op1, op2, op3 PASS_MEM_STAT);
+ extract_ops_from_tree (rhs, &subcode, &op1, &op2, &op3, &op4);
+ return gimple_build_assign (lhs, subcode, op1, op2, op3, op4 PASS_MEM_STAT);
}
@@ -436,7 +436,7 @@ gimple_build_assign (tree lhs, tree rhs MEM_STAT_DECL)
static inline gassign *
gimple_build_assign_1 (tree lhs, enum tree_code subcode, tree op1,
- tree op2, tree op3 MEM_STAT_DECL)
+ tree op2, tree op3, tree op4 MEM_STAT_DECL)
{
unsigned num_ops;
gassign *p;
@@ -462,9 +462,26 @@ gimple_build_assign_1 (tree lhs, enum tree_code subcode, tree op1,
gimple_assign_set_rhs3 (p, op3);
}
+ if (op4)
+ {
+ gcc_assert (num_ops > 4);
+ gimple_assign_set_rhs4 (p, op4);
+ }
+
return p;
}
+/* Build a GIMPLE_ASSIGN statement with subcode SUBCODE and operands
+ OP1, OP2, OP3 and OP4. */
+
+gassign *
+gimple_build_assign (tree lhs, enum tree_code subcode, tree op1,
+ tree op2, tree op3, tree op4 MEM_STAT_DECL)
+{
+ return gimple_build_assign_1 (lhs, subcode, op1, op2, op3, op4 PASS_MEM_STAT);
+}
+
+
/* Build a GIMPLE_ASSIGN statement with subcode SUBCODE and operands
OP1, OP2 and OP3. */
@@ -472,7 +489,8 @@ gassign *
gimple_build_assign (tree lhs, enum tree_code subcode, tree op1,
tree op2, tree op3 MEM_STAT_DECL)
{
- return gimple_build_assign_1 (lhs, subcode, op1, op2, op3 PASS_MEM_STAT);
+ return gimple_build_assign_1 (lhs, subcode, op1, op2, op3,
+ NULL_TREE PASS_MEM_STAT);
}
/* Build a GIMPLE_ASSIGN statement with subcode SUBCODE and operands
@@ -482,7 +500,7 @@ gassign *
gimple_build_assign (tree lhs, enum tree_code subcode, tree op1,
tree op2 MEM_STAT_DECL)
{
- return gimple_build_assign_1 (lhs, subcode, op1, op2, NULL_TREE
+ return gimple_build_assign_1 (lhs, subcode, op1, op2, NULL_TREE, NULL_TREE
PASS_MEM_STAT);
}
@@ -491,8 +509,8 @@ gimple_build_assign (tree lhs, enum tree_code subcode, tree op1,
gassign *
gimple_build_assign (tree lhs, enum tree_code subcode, tree op1 MEM_STAT_DECL)
{
- return gimple_build_assign_1 (lhs, subcode, op1, NULL_TREE, NULL_TREE
- PASS_MEM_STAT);
+ return gimple_build_assign_1 (lhs, subcode, op1, NULL_TREE, NULL_TREE,
+ NULL_TREE PASS_MEM_STAT);
}
@@ -1737,10 +1755,10 @@ void
gimple_assign_set_rhs_from_tree (gimple_stmt_iterator *gsi, tree expr)
{
enum tree_code subcode;
- tree op1, op2, op3;
+ tree op1, op2, op3, op4;
- extract_ops_from_tree (expr, &subcode, &op1, &op2, &op3);
- gimple_assign_set_rhs_with_ops (gsi, subcode, op1, op2, op3);
+ extract_ops_from_tree (expr, &subcode, &op1, &op2, &op3, &op4);
+ gimple_assign_set_rhs_with_ops (gsi, subcode, op1, op2, op3, op4);
}
@@ -1752,7 +1770,7 @@ gimple_assign_set_rhs_from_tree (gimple_stmt_iterator *gsi, tree expr)
void
gimple_assign_set_rhs_with_ops (gimple_stmt_iterator *gsi, enum tree_code code,
- tree op1, tree op2, tree op3)
+ tree op1, tree op2, tree op3, tree op4)
{
unsigned new_rhs_ops = get_gimple_rhs_num_ops (code);
gimple *stmt = gsi_stmt (*gsi);
@@ -1778,6 +1796,8 @@ gimple_assign_set_rhs_with_ops (gimple_stmt_iterator *gsi, enum tree_code code,
gimple_assign_set_rhs2 (stmt, op2);
if (new_rhs_ops > 2)
gimple_assign_set_rhs3 (stmt, op3);
+ if (new_rhs_ops > 3)
+ gimple_assign_set_rhs4 (stmt, op4);
if (stmt != old_stmt)
gsi_replace (gsi, stmt, false);
}
@@ -2233,6 +2253,8 @@ get_gimple_rhs_num_ops (enum tree_code code)
return 2;
else if (rhs_class == GIMPLE_TERNARY_RHS)
return 3;
+ else if (rhs_class == GIMPLE_QUATERNARY_RHS)
+ return 4;
else
gcc_unreachable ();
}
@@ -2264,6 +2286,13 @@ get_gimple_rhs_num_ops (enum tree_code code)
|| (SYM) == ADDR_EXPR \
|| (SYM) == WITH_SIZE_EXPR \
|| (SYM) == SSA_NAME) ? GIMPLE_SINGLE_RHS \
+ : ((SYM) == VEC_COND_LT_EXPR \
+ || (SYM) == VEC_COND_LE_EXPR \
+ || (SYM) == VEC_COND_LE_EXPR \
+ || (SYM) == VEC_COND_GT_EXPR \
+ || (SYM) == VEC_COND_GE_EXPR \
+ || (SYM) == VEC_COND_EQ_EXPR \
+ || (SYM) == VEC_COND_NE_EXPR) ? GIMPLE_QUATERNARY_RHS \
: GIMPLE_INVALID_RHS),
#define END_OF_BASE_TREE_CODES (unsigned char) GIMPLE_INVALID_RHS,
@@ -3269,6 +3298,47 @@ gimple_inexpensive_call_p (gcall *stmt)
return false;
}
+gassign *
+gimple_build_vec_cond_expr (tree lhs, tree condition, tree then_clause,
+ tree else_clause)
+{
+ tree cond_lhs, cond_rhs;
+ tree_code code;
+
+ if (TREE_CODE (condition) == SSA_NAME)
+ {
+ gimple *stmt = SSA_NAME_DEF_STMT (condition);
+ code = gimple_assign_rhs_code (stmt);
+ if (TREE_CODE_CLASS (code) == tcc_comparison)
+ {
+ code = cmp_to_vec_cmp_code (code);
+ cond_lhs = gimple_assign_rhs1 (stmt);
+ cond_rhs = gimple_assign_rhs2 (stmt);
+ }
+ else
+ {
+ code = VEC_COND_EQ_EXPR;
+ cond_lhs = condition;
+ cond_rhs = constant_boolean_node (true, TREE_TYPE (condition));
+ }
+ }
+ else if (TREE_CODE (condition) == VECTOR_CST)
+ {
+ // TODO: this should be probably folded right away
+ code = VEC_COND_EQ_EXPR;
+ cond_lhs = condition;
+ cond_rhs = constant_boolean_node (true, TREE_TYPE (condition));
+ }
+ else
+ {
+ code = cmp_to_vec_cmp_code (TREE_CODE (condition));
+ cond_lhs = TREE_OPERAND (condition, 0);
+ cond_rhs = TREE_OPERAND (condition, 1);
+ }
+ return gimple_build_assign (lhs, code, cond_lhs, cond_rhs, then_clause,
+ else_clause);
+}
+
#if CHECKING_P
namespace selftest {
diff --git a/gcc/gimple.h b/gcc/gimple.h
index cf1f8da5ae2..6d404019c5a 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -115,12 +115,13 @@ GIMPLE_CHECK2(const gimple *gs)
get_gimple_rhs_class. */
enum gimple_rhs_class
{
- GIMPLE_INVALID_RHS, /* The expression cannot be used on the RHS. */
- GIMPLE_TERNARY_RHS, /* The expression is a ternary operation. */
- GIMPLE_BINARY_RHS, /* The expression is a binary operation. */
- GIMPLE_UNARY_RHS, /* The expression is a unary operation. */
- GIMPLE_SINGLE_RHS /* The expression is a single object (an SSA
- name, a _DECL, a _REF, etc. */
+ GIMPLE_INVALID_RHS, /* The expression cannot be used on the RHS. */
+ GIMPLE_QUATERNARY_RHS, /* The expression is a quoternary operation. */
+ GIMPLE_TERNARY_RHS, /* The expression is a ternary operation. */
+ GIMPLE_BINARY_RHS, /* The expression is a binary operation. */
+ GIMPLE_UNARY_RHS, /* The expression is a unary operation. */
+ GIMPLE_SINGLE_RHS /* The expression is a single object (an SSA
+ name, a _DECL, a _REF, etc. */
};
/* Specific flags for individual GIMPLE statements. These flags are
@@ -1457,11 +1458,15 @@ gcall *gimple_build_call_internal (enum internal_fn, unsigned, ...);
gcall *gimple_build_call_internal_vec (enum internal_fn, vec<tree> );
gcall *gimple_build_call_from_tree (tree, tree);
gassign *gimple_build_assign (tree, tree CXX_MEM_STAT_INFO);
+gassign *gimple_build_assign (tree, enum tree_code,
+ tree, tree, tree, tree CXX_MEM_STAT_INFO);
gassign *gimple_build_assign (tree, enum tree_code,
tree, tree, tree CXX_MEM_STAT_INFO);
gassign *gimple_build_assign (tree, enum tree_code,
tree, tree CXX_MEM_STAT_INFO);
gassign *gimple_build_assign (tree, enum tree_code, tree CXX_MEM_STAT_INFO);
+gassign *gimple_build_vec_cond_expr (tree, tree, tree, tree);
+
gcond *gimple_build_cond (enum tree_code, tree, tree, tree, tree);
gcond *gimple_build_cond_from_tree (tree, tree, tree);
void gimple_cond_set_condition_from_tree (gcond *, tree);
@@ -1530,7 +1535,7 @@ bool gimple_assign_unary_nop_p (gimple *);
void gimple_set_bb (gimple *, basic_block);
void gimple_assign_set_rhs_from_tree (gimple_stmt_iterator *, tree);
void gimple_assign_set_rhs_with_ops (gimple_stmt_iterator *, enum tree_code,
- tree, tree, tree);
+ tree, tree, tree, tree);
tree gimple_get_lhs (const gimple *);
void gimple_set_lhs (gimple *, tree);
gimple *gimple_copy (gimple *);
@@ -2686,24 +2691,82 @@ gimple_assign_set_rhs3 (gimple *gs, tree rhs)
}
-/* A wrapper around 3 operand gimple_assign_set_rhs_with_ops, for callers
+/* Return the fourth operand on the RHS of assignment statement GS.
+ If GS does not have two operands, NULL is returned instead. */
+
+static inline tree
+gimple_assign_rhs4 (const gassign *gs)
+{
+ if (gimple_num_ops (gs) >= 5)
+ return gs->op[4];
+ else
+ return NULL_TREE;
+}
+
+static inline tree
+gimple_assign_rhs4 (const gimple *gs)
+{
+ const gassign *ass = GIMPLE_CHECK2<const gassign *> (gs);
+ return gimple_assign_rhs4 (ass);
+}
+
+/* Return a pointer to the fourth operand on the RHS of assignment
+ statement GS. */
+
+static inline tree *
+gimple_assign_rhs4_ptr (gimple *gs)
+{
+ gassign *ass = GIMPLE_CHECK2<gassign *> (gs);
+ gcc_gimple_checking_assert (gimple_num_ops (gs) >= 5);
+ return &ass->op[4];
+}
+
+
+/* Set RHS to be the fourth operand on the RHS of assignment statement GS. */
+
+static inline void
+gimple_assign_set_rhs4 (gassign *gs, tree rhs)
+{
+ gcc_gimple_checking_assert (gimple_num_ops (gs) >= 5);
+ gs->op[4] = rhs;
+}
+
+static inline void
+gimple_assign_set_rhs4 (gimple *gs, tree rhs)
+{
+ gassign *ass = GIMPLE_CHECK2<gassign *> (gs);
+ gimple_assign_set_rhs4 (ass, rhs);
+}
+
+/* A wrapper around 4 operand gimple_assign_set_rhs_with_ops, for callers
+ which expect to see only three operands. */
+
+static inline void
+gimple_assign_set_rhs_with_ops (gimple_stmt_iterator *gsi, enum tree_code code,
+ tree op1, tree op2, tree op3)
+{
+ gimple_assign_set_rhs_with_ops (gsi, code, op1, op2, op3, NULL);
+}
+
+
+/* A wrapper around 4 operand gimple_assign_set_rhs_with_ops, for callers
which expect to see only two operands. */
static inline void
gimple_assign_set_rhs_with_ops (gimple_stmt_iterator *gsi, enum tree_code code,
tree op1, tree op2)
{
- gimple_assign_set_rhs_with_ops (gsi, code, op1, op2, NULL);
+ gimple_assign_set_rhs_with_ops (gsi, code, op1, op2, NULL, NULL);
}
-/* A wrapper around 3 operand gimple_assign_set_rhs_with_ops, for callers
+/* A wrapper around 4 operand gimple_assign_set_rhs_with_ops, for callers
which expect to see only one operands. */
static inline void
gimple_assign_set_rhs_with_ops (gimple_stmt_iterator *gsi, enum tree_code code,
tree op1)
{
- gimple_assign_set_rhs_with_ops (gsi, code, op1, NULL, NULL);
+ gimple_assign_set_rhs_with_ops (gsi, code, op1, NULL, NULL, NULL);
}
/* Returns true if GS is a nontemporal move. */
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 623cdbfed7c..fb2797e3ee8 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -13812,19 +13812,20 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
case VEC_COND_EXPR:
{
- enum gimplify_status r0, r1, r2;
-
- r0 = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p,
- post_p, is_gimple_condexpr, fb_rvalue);
- r1 = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p,
- post_p, is_gimple_val, fb_rvalue);
- r2 = gimplify_expr (&TREE_OPERAND (*expr_p, 2), pre_p,
- post_p, is_gimple_val, fb_rvalue);
-
- ret = MIN (MIN (r0, r1), r2);
- recalculate_side_effects (*expr_p);
+ tree type = TREE_TYPE (TREE_OPERAND (*expr_p, 1));
+ tree cond_expr = TREE_OPERAND (*expr_p, 0);
+ tree_code vec_code = cmp_to_vec_cmp_code (TREE_CODE (cond_expr));
+ *expr_p = build4_loc (input_location, vec_code, type,
+ TREE_OPERAND (cond_expr, 0),
+ TREE_OPERAND (cond_expr, 1),
+ TREE_OPERAND (*expr_p, 1),
+ TREE_OPERAND (*expr_p, 2));
+
+ goto expr_4;
}
- break;
+
+ CASE_VEC_COND_EXPR:
+ goto expr_4;
case VEC_PERM_EXPR:
/* Classified as tcc_expression. */
@@ -13923,6 +13924,23 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
break;
}
+ expr_4:
+ {
+ enum gimplify_status r0, r1, r2, r3;
+
+ r0 = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p,
+ post_p, is_gimple_val, fb_rvalue);
+ r1 = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p,
+ post_p, is_gimple_val, fb_rvalue);
+ r2 = gimplify_expr (&TREE_OPERAND (*expr_p, 2), pre_p,
+ post_p, is_gimple_val, fb_rvalue);
+ r3 = gimplify_expr (&TREE_OPERAND (*expr_p, 3), pre_p,
+ post_p, is_gimple_val, fb_rvalue);
+
+ ret = MIN (MIN (r0, r1), MIN (r2, r3));
+ break;
+ }
+
case tcc_declaration:
case tcc_constant:
ret = GS_ALL_DONE;
diff --git a/gcc/optabs.c b/gcc/optabs.c
index 35921e691f9..b40cb1b7a0b 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -5822,43 +5822,21 @@ expand_vec_cond_mask_expr (tree vec_cond_type, tree op0, tree op1, tree op2,
three operands. */
rtx
-expand_vec_cond_expr (tree vec_cond_type, tree op0, tree op1, tree op2,
- rtx target)
+expand_vec_cond_expr (tree vec_cond_type, tree_code tcode,
+ tree cond_lhs, tree cond_rhs, tree if_true,
+ tree if_false, rtx target)
{
class expand_operand ops[6];
enum insn_code icode;
- rtx comparison, rtx_op1, rtx_op2;
machine_mode mode = TYPE_MODE (vec_cond_type);
machine_mode cmp_op_mode;
bool unsignedp;
- tree op0a, op0b;
- enum tree_code tcode;
- if (COMPARISON_CLASS_P (op0))
- {
- op0a = TREE_OPERAND (op0, 0);
- op0b = TREE_OPERAND (op0, 1);
- tcode = TREE_CODE (op0);
- }
- else
- {
- gcc_assert (VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (op0)));
- if (get_vcond_mask_icode (mode, TYPE_MODE (TREE_TYPE (op0)))
- != CODE_FOR_nothing)
- return expand_vec_cond_mask_expr (vec_cond_type, op0, op1,
- op2, target);
- /* Fake op0 < 0. */
- else
- {
- gcc_assert (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (op0)))
- == MODE_VECTOR_INT);
- op0a = op0;
- op0b = build_zero_cst (TREE_TYPE (op0));
- tcode = LT_EXPR;
- }
- }
- cmp_op_mode = TYPE_MODE (TREE_TYPE (op0a));
- unsignedp = TYPE_UNSIGNED (TREE_TYPE (op0a));
+ tcode = vec_cmp_to_cmp_code (tcode);
+
+ // TODO: maybe add sanity check
+ cmp_op_mode = TYPE_MODE (TREE_TYPE (cond_lhs));
+ unsignedp = TYPE_UNSIGNED (TREE_TYPE (cond_lhs));
gcc_assert (known_eq (GET_MODE_SIZE (mode), GET_MODE_SIZE (cmp_op_mode))
@@ -5869,21 +5847,20 @@ expand_vec_cond_expr (tree vec_cond_type, tree op0, tree op1, tree op2,
if (icode == CODE_FOR_nothing)
{
if (tcode == LT_EXPR
- && op0a == op0
- && TREE_CODE (op0) == VECTOR_CST)
+ && TREE_CODE (cond_lhs) == VECTOR_CST)
{
/* A VEC_COND_EXPR condition could be folded from EQ_EXPR/NE_EXPR
into a constant when only get_vcond_eq_icode is supported.
Verify < 0 and != 0 behave the same and change it to NE_EXPR. */
unsigned HOST_WIDE_INT nelts;
- if (!VECTOR_CST_NELTS (op0).is_constant (&nelts))
+ if (!VECTOR_CST_NELTS (cond_lhs).is_constant (&nelts))
{
- if (VECTOR_CST_STEPPED_P (op0))
+ if (VECTOR_CST_STEPPED_P (cond_lhs))
return 0;
- nelts = vector_cst_encoded_nelts (op0);
+ nelts = vector_cst_encoded_nelts (cond_lhs);
}
for (unsigned int i = 0; i < nelts; ++i)
- if (tree_int_cst_sgn (vector_cst_elt (op0, i)) == 1)
+ if (tree_int_cst_sgn (vector_cst_elt (cond_lhs, i)) == 1)
return 0;
tcode = NE_EXPR;
}
@@ -5893,14 +5870,14 @@ expand_vec_cond_expr (tree vec_cond_type, tree op0, tree op1, tree op2,
return 0;
}
- comparison = vector_compare_rtx (VOIDmode, tcode, op0a, op0b, unsignedp,
- icode, 4);
- rtx_op1 = expand_normal (op1);
- rtx_op2 = expand_normal (op2);
+ rtx comparison = vector_compare_rtx (VOIDmode, tcode, cond_lhs, cond_rhs,
+ unsignedp, icode, 4);
+ rtx rtx_true = expand_normal (if_true);
+ rtx rtx_false = expand_normal (if_false);
create_output_operand (&ops[0], target, mode);
- create_input_operand (&ops[1], rtx_op1, mode);
- create_input_operand (&ops[2], rtx_op2, mode);
+ create_input_operand (&ops[1], rtx_true, mode);
+ create_input_operand (&ops[2], rtx_false, mode);
create_fixed_operand (&ops[3], comparison);
create_fixed_operand (&ops[4], XEXP (comparison, 0));
create_fixed_operand (&ops[5], XEXP (comparison, 1));
diff --git a/gcc/optabs.h b/gcc/optabs.h
index 897bb5d4443..df72cc7910b 100644
--- a/gcc/optabs.h
+++ b/gcc/optabs.h
@@ -315,7 +315,7 @@ extern rtx expand_vec_perm_const (machine_mode, rtx, rtx,
extern rtx expand_vec_cmp_expr (tree, tree, rtx);
/* Generate code for VEC_COND_EXPR. */
-extern rtx expand_vec_cond_expr (tree, tree, tree, tree, rtx);
+extern rtx expand_vec_cond_expr (tree, tree_code, tree, tree, tree, tree, rtx);
/* Generate code for VEC_SERIES_EXPR. */
extern rtx expand_vec_series_expr (machine_mode, rtx, rtx, rtx);
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index b75fdb2e63f..1eae627b49b 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -4152,20 +4152,9 @@ verify_gimple_assign_ternary (gassign *stmt)
return true;
}
break;
-
case VEC_COND_EXPR:
- if (!VECTOR_BOOLEAN_TYPE_P (rhs1_type)
- || maybe_ne (TYPE_VECTOR_SUBPARTS (rhs1_type),
- TYPE_VECTOR_SUBPARTS (lhs_type)))
- {
- error ("the first argument of a %qs must be of a "
- "boolean vector type of the same number of elements "
- "as the result", code_name);
- debug_generic_expr (lhs_type);
- debug_generic_expr (rhs1_type);
- return true;
- }
- /* Fallthrough. */
+ error ("%qs in gimple IL", code_name);
+ return true;
case COND_EXPR:
if (!is_gimple_val (rhs1)
&& verify_gimple_comparison (TREE_TYPE (rhs1),
@@ -4364,6 +4353,90 @@ verify_gimple_assign_ternary (gassign *stmt)
return false;
}
+/* Verify a gimple assignment statement STMT with a quaternary rhs.
+ Returns true if anything is wrong. */
+
+static bool
+verify_gimple_assign_quaternary (gassign *stmt)
+{
+ enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
+ tree lhs = gimple_assign_lhs (stmt);
+ tree lhs_type = TREE_TYPE (lhs);
+ tree rhs1 = gimple_assign_rhs1 (stmt);
+ tree rhs1_type = TREE_TYPE (rhs1);
+ tree rhs2 = gimple_assign_rhs2 (stmt);
+ tree rhs2_type = TREE_TYPE (rhs2);
+ tree rhs3 = gimple_assign_rhs3 (stmt);
+ tree rhs3_type = TREE_TYPE (rhs3);
+ tree rhs4 = gimple_assign_rhs4 (stmt);
+ tree rhs4_type = TREE_TYPE (rhs4);
+
+ const char* const code_name = get_tree_code_name (rhs_code);
+
+ if (!is_gimple_reg (lhs))
+ {
+ error ("non-register as LHS of ternary operation");
+ return true;
+ }
+
+ /* First handle operations that involve different types. */
+ switch (rhs_code)
+ {
+ CASE_VEC_COND_EXPR:
+ if (TREE_CODE (rhs1_type) != VECTOR_TYPE
+ || TREE_CODE (rhs2_type) != VECTOR_TYPE
+ || TREE_CODE (rhs3_type) != VECTOR_TYPE
+ || TREE_CODE (rhs4_type) != VECTOR_TYPE)
+ {
+ error ("vector types expected in %qs", code_name);
+ debug_generic_expr (lhs_type);
+ debug_generic_expr (rhs1_type);
+ debug_generic_expr (rhs2_type);
+ debug_generic_expr (rhs3_type);
+ debug_generic_expr (rhs4_type);
+ return true;
+ }
+ if (maybe_ne (TYPE_VECTOR_SUBPARTS (rhs1_type),
+ TYPE_VECTOR_SUBPARTS (rhs2_type))
+ || maybe_ne (TYPE_VECTOR_SUBPARTS (rhs2_type),
+ TYPE_VECTOR_SUBPARTS (rhs3_type))
+ || maybe_ne (TYPE_VECTOR_SUBPARTS (rhs3_type),
+ TYPE_VECTOR_SUBPARTS (rhs4_type))
+ || maybe_ne (TYPE_VECTOR_SUBPARTS (rhs4_type),
+ TYPE_VECTOR_SUBPARTS (lhs_type)))
+ {
+ error ("vectors with different element number found in %qs",
+ code_name);
+ debug_generic_expr (lhs_type);
+ debug_generic_expr (rhs1_type);
+ debug_generic_expr (rhs2_type);
+ debug_generic_expr (rhs3_type);
+ debug_generic_expr (rhs4_type);
+ return true;
+ }
+ if (!useless_type_conversion_p (lhs_type, rhs3_type)
+ || !useless_type_conversion_p (lhs_type, rhs4_type)
+ || !useless_type_conversion_p (rhs1_type, rhs2_type))
+ {
+ error ("type mismatch in %qs", code_name);
+ debug_generic_expr (lhs_type);
+ debug_generic_expr (rhs1_type);
+ debug_generic_expr (rhs2_type);
+ debug_generic_expr (rhs3_type);
+ debug_generic_expr (rhs4_type);
+ return true;
+ }
+
+ // TODO: add from COND_EXPR
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ return false;
+}
+
+
/* Verify a gimple assignment statement STMT with a single rhs.
Returns true if anything is wrong. */
@@ -4617,6 +4690,9 @@ verify_gimple_assign (gassign *stmt)
case GIMPLE_TERNARY_RHS:
return verify_gimple_assign_ternary (stmt);
+ case GIMPLE_QUATERNARY_RHS:
+ return verify_gimple_assign_quaternary (stmt);
+
default:
gcc_unreachable ();
}
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index e4ae1b058fd..a5034dc862b 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -4092,7 +4092,7 @@ estimate_operator_cost (enum tree_code code, eni_weights *weights,
/* Assign cost of 1 to usual operations.
??? We may consider mapping RTL costs to this. */
case COND_EXPR:
- case VEC_COND_EXPR:
+ CASE_VEC_COND_EXPR:
case VEC_PERM_EXPR:
case PLUS_EXPR:
diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c
index c464c899586..5c1a250bd55 100644
--- a/gcc/tree-ssa-forwprop.c
+++ b/gcc/tree-ssa-forwprop.c
@@ -347,7 +347,13 @@ rhs_to_tree (tree type, gimple *stmt)
{
location_t loc = gimple_location (stmt);
enum tree_code code = gimple_assign_rhs_code (stmt);
- if (get_gimple_rhs_class (code) == GIMPLE_TERNARY_RHS)
+ // TODO: use fold_build4_loc
+ if (get_gimple_rhs_class (code) == GIMPLE_QUATERNARY_RHS)
+ return build4_loc (loc, code, type, gimple_assign_rhs1 (stmt),
+ gimple_assign_rhs2 (stmt),
+ gimple_assign_rhs3 (stmt),
+ gimple_assign_rhs4 (stmt));
+ else if (get_gimple_rhs_class (code) == GIMPLE_TERNARY_RHS)
return fold_build3_loc (loc, code, type, gimple_assign_rhs1 (stmt),
gimple_assign_rhs2 (stmt),
gimple_assign_rhs3 (stmt));
@@ -2164,7 +2170,7 @@ simplify_vector_constructor (gimple_stmt_iterator *gsi)
gimple_assign_set_rhs_from_tree (gsi, orig[0]);
else
gimple_assign_set_rhs_with_ops (gsi, conv_code, orig[0],
- NULL_TREE, NULL_TREE);
+ NULL_TREE);
}
else
{
@@ -2224,8 +2230,7 @@ simplify_vector_constructor (gimple_stmt_iterator *gsi)
VEC_PERM_EXPR, orig[0], orig[1], op2);
orig[0] = gimple_assign_lhs (perm);
gsi_insert_before (gsi, perm, GSI_SAME_STMT);
- gimple_assign_set_rhs_with_ops (gsi, conv_code, orig[0],
- NULL_TREE, NULL_TREE);
+ gimple_assign_set_rhs_with_ops (gsi, conv_code, orig[0]);
}
}
update_stmt (gsi_stmt (*gsi));
diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c
index cd2ced36971..7f2b96a1bf0 100644
--- a/gcc/tree-ssa-loop-niter.c
+++ b/gcc/tree-ssa-loop-niter.c
@@ -3177,9 +3177,9 @@ static widest_int
derive_constant_upper_bound (tree val)
{
enum tree_code code;
- tree op0, op1, op2;
+ tree op0, op1, op2, op3;
- extract_ops_from_tree (val, &code, &op0, &op1, &op2);
+ extract_ops_from_tree (val, &code, &op0, &op1, &op2, &op3);
return derive_constant_upper_bound_ops (TREE_TYPE (val), op0, code, op1);
}
diff --git a/gcc/tree-ssa-operands.c b/gcc/tree-ssa-operands.c
index e643b33a6b0..a09229c470e 100644
--- a/gcc/tree-ssa-operands.c
+++ b/gcc/tree-ssa-operands.c
@@ -797,7 +797,6 @@ get_expr_operands (struct function *fn, gimple *stmt, tree *expr_p, int flags)
return;
case COND_EXPR:
- case VEC_COND_EXPR:
case VEC_PERM_EXPR:
get_expr_operands (fn, stmt, &TREE_OPERAND (expr, 0), uflags);
get_expr_operands (fn, stmt, &TREE_OPERAND (expr, 1), uflags);
diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c
index c618601a184..478530a5ad2 100644
--- a/gcc/tree-ssa-pre.c
+++ b/gcc/tree-ssa-pre.c
@@ -3875,11 +3875,11 @@ compute_avail (void)
enum tree_code code = gimple_assign_rhs_code (stmt);
vn_nary_op_t nary;
- /* COND_EXPR and VEC_COND_EXPR are awkward in
+ /* COND_EXPR and VEC_COND_*_EXPR are awkward in
that they contain an embedded complex expression.
Don't even try to shove those through PRE. */
if (code == COND_EXPR
- || code == VEC_COND_EXPR)
+ || vec_cond_expr_p (code))
continue;
vn_nary_op_lookup_stmt (stmt, &nary);
diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c
index 510dfd1e188..01ec9701bfb 100644
--- a/gcc/tree-ssa-reassoc.c
+++ b/gcc/tree-ssa-reassoc.c
@@ -3747,7 +3747,7 @@ optimize_range_tests (enum tree_code opcode,
}
/* A subroutine of optimize_vec_cond_expr to extract and canonicalize
- the operands of the VEC_COND_EXPR. Returns ERROR_MARK on failure,
+ the operands of the VEC_COND_*_EXPR. Returns ERROR_MARK on failure,
otherwise the comparison code. TYPE is a return value that is set
to type of comparison. */
@@ -3763,7 +3763,7 @@ ovce_extract_ops (tree var, gassign **rets, bool *reti, tree *type)
/* ??? If we start creating more COND_EXPR, we could perform
this same optimization with them. For now, simplify. */
- if (gimple_assign_rhs_code (stmt) != VEC_COND_EXPR)
+ if (!vec_cond_expr_p (gimple_assign_rhs_code (stmt)))
return ERROR_MARK;
tree cond = gimple_assign_rhs1 (stmt);
diff --git a/gcc/tree-ssa-scopedtables.c b/gcc/tree-ssa-scopedtables.c
index 574bc30eee1..05b56ef8a88 100644
--- a/gcc/tree-ssa-scopedtables.c
+++ b/gcc/tree-ssa-scopedtables.c
@@ -432,6 +432,15 @@ add_hashable_expr (const struct hashable_expr *expr, hash &hstate)
inchash::add_expr (expr->ops.ternary.opnd2, hstate);
break;
+ case EXPR_QUATERNARY:
+ hstate.add_object (expr->ops.quaternary.op);
+ inchash::add_expr (expr->ops.quaternary.opnd0, hstate);
+ inchash::add_expr (expr->ops.quaternary.opnd1, hstate);
+ inchash::add_expr (expr->ops.quaternary.opnd2, hstate);
+ inchash::add_expr (expr->ops.quaternary.opnd3, hstate);
+ break;
+
+
case EXPR_CALL:
{
size_t i;
@@ -643,6 +652,19 @@ hashable_expr_equal_p (const struct hashable_expr *expr0,
&& operand_equal_p (expr0->ops.ternary.opnd1,
expr1->ops.ternary.opnd0, 0));
+ case EXPR_QUATERNARY:
+ if (expr0->ops.quaternary.op != expr1->ops.quaternary.op)
+ return false;
+
+ return (operand_equal_p (expr0->ops.quaternary.opnd0,
+ expr1->ops.quaternary.opnd0, 0)
+ && operand_equal_p (expr0->ops.quaternary.opnd1,
+ expr1->ops.quaternary.opnd1, 0)
+ && operand_equal_p (expr0->ops.quaternary.opnd2,
+ expr1->ops.quaternary.opnd2, 0)
+ && operand_equal_p (expr0->ops.quaternary.opnd3,
+ expr1->ops.quaternary.opnd3, 0));
+
case EXPR_CALL:
{
size_t i;
@@ -736,6 +758,16 @@ expr_hash_elt::expr_hash_elt (gimple *stmt, tree orig_lhs)
expr->ops.ternary.opnd1 = gimple_assign_rhs2 (stmt);
expr->ops.ternary.opnd2 = gimple_assign_rhs3 (stmt);
break;
+ case GIMPLE_QUATERNARY_RHS:
+ expr->kind = EXPR_TERNARY;
+ expr->type = TREE_TYPE (gimple_assign_lhs (stmt));
+ expr->ops.quaternary.op = subcode;
+ expr->ops.quaternary.opnd0 = gimple_assign_rhs1 (stmt);
+ expr->ops.quaternary.opnd1 = gimple_assign_rhs2 (stmt);
+ expr->ops.quaternary.opnd2 = gimple_assign_rhs3 (stmt);
+ expr->ops.quaternary.opnd3 = gimple_assign_rhs4 (stmt);
+ break;
+
default:
gcc_unreachable ();
}
@@ -896,6 +928,18 @@ expr_hash_elt::print (FILE *stream)
fputs (">", stream);
break;
+ case EXPR_QUATERNARY:
+ fprintf (stream, " %s <", get_tree_code_name (m_expr.ops.quaternary.op));
+ print_generic_expr (stream, m_expr.ops.quaternary.opnd0);
+ fputs (", ", stream);
+ print_generic_expr (stream, m_expr.ops.quaternary.opnd1);
+ fputs (", ", stream);
+ print_generic_expr (stream, m_expr.ops.quaternary.opnd2);
+ fputs (", ", stream);
+ print_generic_expr (stream, m_expr.ops.quaternary.opnd3);
+ fputs (">", stream);
+ break;
+
case EXPR_CALL:
{
size_t i;
diff --git a/gcc/tree-ssa-scopedtables.h b/gcc/tree-ssa-scopedtables.h
index 48185006823..e3ed5c5e753 100644
--- a/gcc/tree-ssa-scopedtables.h
+++ b/gcc/tree-ssa-scopedtables.h
@@ -29,6 +29,7 @@ enum expr_kind
EXPR_UNARY,
EXPR_BINARY,
EXPR_TERNARY,
+ EXPR_QUATERNARY,
EXPR_CALL,
EXPR_PHI
};
@@ -42,6 +43,7 @@ struct hashable_expr
struct { enum tree_code op; tree opnd; } unary;
struct { enum tree_code op; tree opnd0, opnd1; } binary;
struct { enum tree_code op; tree opnd0, opnd1, opnd2; } ternary;
+ struct { enum tree_code op; tree opnd0, opnd1, opnd2, opnd3; } quaternary;
struct { gcall *fn_from; bool pure; size_t nargs; tree *args; } call;
struct { size_t nargs; tree *args; } phi;
} ops;
diff --git a/gcc/tree-vect-generic.c b/gcc/tree-vect-generic.c
index 5855653257b..34a9a1b39e8 100644
--- a/gcc/tree-vect-generic.c
+++ b/gcc/tree-vect-generic.c
@@ -373,8 +373,9 @@ expand_vector_addition (gimple_stmt_iterator *gsi,
/* Try to expand vector comparison expression OP0 CODE OP1 by
querying optab if the following expression:
- VEC_COND_EXPR< OP0 CODE OP1, {-1,...}, {0,...}>
+ VEC_COND_CODE_EXPR< OP0, OP1, {-1,...}, {0,...}>
can be expanded. */
+
static tree
expand_vector_comparison (gimple_stmt_iterator *gsi, tree type, tree op0,
tree op1, enum tree_code code)
@@ -691,12 +692,10 @@ expand_vector_divmod (gimple_stmt_iterator *gsi, tree type, tree op0,
if (addend == NULL_TREE
&& expand_vec_cond_expr_p (type, type, LT_EXPR))
{
- tree zero, cst, cond, mask_type;
+ tree zero, cst;
gimple *stmt;
- mask_type = build_same_sized_truth_vector_type (type);
zero = build_zero_cst (type);
- cond = build2 (LT_EXPR, mask_type, op0, zero);
tree_vector_builder vec (type, nunits, 1);
for (i = 0; i < nunits; i++)
vec.quick_push (build_int_cst (TREE_TYPE (type),
@@ -704,7 +703,7 @@ expand_vector_divmod (gimple_stmt_iterator *gsi, tree type, tree op0,
<< shifts[i]) - 1));
cst = vec.build ();
addend = make_ssa_name (type);
- stmt = gimple_build_assign (addend, VEC_COND_EXPR, cond,
+ stmt = gimple_build_assign (addend, VEC_COND_LT_EXPR, op0, zero,
cst, zero);
gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
}
@@ -1964,7 +1963,7 @@ expand_vector_operations_1 (gimple_stmt_iterator *gsi)
return;
}
- if (code == VEC_COND_EXPR)
+ if (vec_cond_expr_p (code))
{
expand_vector_condition (gsi);
return;
diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c
index e952713d131..536b46cd44b 100644
--- a/gcc/tree-vect-loop.c
+++ b/gcc/tree-vect-loop.c
@@ -4473,7 +4473,7 @@ vect_create_epilog_for_reduction (vec<tree> vect_defs,
poly_uint64 nunits_out = TYPE_VECTOR_SUBPARTS (vectype);
gimple *vec_stmt = STMT_VINFO_VEC_STMT (stmt_info)->stmt;
- gcc_assert (gimple_assign_rhs_code (vec_stmt) == VEC_COND_EXPR);
+ gcc_assert (vec_cond_expr_p (gimple_assign_rhs_code (vec_stmt)));
int scalar_precision
= GET_MODE_PRECISION (SCALAR_TYPE_MODE (TREE_TYPE (vectype)));
@@ -4521,14 +4521,14 @@ vect_create_epilog_for_reduction (vec<tree> vect_defs,
Finally, we update the phi (NEW_PHI_TREE) to take the value of
the new cond_expr (INDEX_COND_EXPR). */
- /* Duplicate the condition from vec_stmt. */
- tree ccompare = unshare_expr (gimple_assign_rhs1 (vec_stmt));
-
/* Create a conditional, where the condition is taken from vec_stmt
(CCOMPARE), then is the induction index (INDEX_BEFORE_INCR) and
else is the phi (NEW_PHI_TREE). */
- tree index_cond_expr = build3 (VEC_COND_EXPR, cr_index_vector_type,
- ccompare, indx_before_incr,
+ tree index_cond_expr = build4 (gimple_assign_rhs_code (vec_stmt),
+ cr_index_vector_type,
+ gimple_assign_rhs1 (vec_stmt),
+ gimple_assign_rhs2 (vec_stmt),
+ indx_before_incr,
new_phi_tree);
induction_index = make_ssa_name (cr_index_vector_type);
gimple *index_condition = gimple_build_assign (induction_index,
@@ -4750,8 +4750,6 @@ vect_create_epilog_for_reduction (vec<tree> vect_defs,
tree index_vec_type = TREE_TYPE (induction_index);
gcc_checking_assert (TYPE_UNSIGNED (index_vec_type));
tree index_scalar_type = TREE_TYPE (index_vec_type);
- tree index_vec_cmp_type = build_same_sized_truth_vector_type
- (index_vec_type);
/* Get an unsigned integer version of the type of the data vector. */
int scalar_precision
@@ -4794,22 +4792,16 @@ vect_create_epilog_for_reduction (vec<tree> vect_defs,
(VEC_COND) with one data value and the rest zeros.
In the case where the loop never made any matches, every index will
match, resulting in a vector with all data values (which will all be
- the default value). */
-
- /* Compare the max index vector to the vector of found indexes to find
+ the default value).
+ Compare the max index vector to the vector of found indexes to find
the position of the max value. */
- tree vec_compare = make_ssa_name (index_vec_cmp_type);
- gimple *vec_compare_stmt = gimple_build_assign (vec_compare, EQ_EXPR,
- induction_index,
- max_index_vec);
- gsi_insert_before (&exit_gsi, vec_compare_stmt, GSI_SAME_STMT);
/* Use the compare to choose either values from the data vector or
zero. */
tree vec_cond = make_ssa_name (vectype);
- gimple *vec_cond_stmt = gimple_build_assign (vec_cond, VEC_COND_EXPR,
- vec_compare, new_phi_result,
- zero_vec);
+ gimple *vec_cond_stmt = gimple_build_assign (vec_cond, VEC_COND_EQ_EXPR,
+ induction_index, max_index_vec,
+ new_phi_result, zero_vec);
gsi_insert_before (&exit_gsi, vec_cond_stmt, GSI_SAME_STMT);
/* Finally we need to extract the data value from the vector (VEC_COND)
@@ -5042,8 +5034,10 @@ vect_create_epilog_for_reduction (vec<tree> vect_defs,
vec = seq ? new_phi_result : vector_identity;
VEC is now suitable for a full vector reduction. */
- tree vec = gimple_build (&seq, VEC_COND_EXPR, vectype,
- sel, new_phi_result, vector_identity);
+ tree vec = make_ssa_name (new_phi_result);
+ gimple *cond_expr = gimple_build_vec_cond_expr (vec, sel, new_phi_result,
+ vector_identity);
+ gimple_seq_add_stmt (&seq, cond_expr);
/* Do the reduction and convert it to the appropriate type. */
tree scalar = gimple_build (&seq, as_combined_fn (reduc_fn),
@@ -5644,8 +5638,7 @@ merge_with_identity (gimple_stmt_iterator *gsi, tree mask, tree vectype,
tree vec, tree identity)
{
tree cond = make_temp_ssa_name (vectype, NULL, "cond");
- gimple *new_stmt = gimple_build_assign (cond, VEC_COND_EXPR,
- mask, vec, identity);
+ gimple *new_stmt = gimple_build_vec_cond_expr (cond, mask, vec, identity);
gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT);
return cond;
}
@@ -5946,8 +5939,8 @@ build_vect_cond_expr (enum tree_code code, tree vop[3], tree mask,
tree vectype = TREE_TYPE (vop[1]);
tree zero = build_zero_cst (vectype);
tree masked_op1 = make_temp_ssa_name (vectype, NULL, "masked_op1");
- gassign *select = gimple_build_assign (masked_op1, VEC_COND_EXPR,
- mask, vop[1], zero);
+ gassign *select = gimple_build_vec_cond_expr (masked_op1, mask,
+ vop[1], zero);
gsi_insert_before (gsi, select, GSI_SAME_STMT);
vop[1] = masked_op1;
break;
@@ -5957,8 +5950,8 @@ build_vect_cond_expr (enum tree_code code, tree vop[3], tree mask,
{
tree vectype = TREE_TYPE (vop[1]);
tree masked_op1 = make_temp_ssa_name (vectype, NULL, "masked_op1");
- gassign *select = gimple_build_assign (masked_op1, VEC_COND_EXPR,
- mask, vop[1], vop[0]);
+ gassign *select = gimple_build_vec_cond_expr (masked_op1, mask,
+ vop[1], vop[0]);
gsi_insert_before (gsi, select, GSI_SAME_STMT);
vop[1] = masked_op1;
break;
@@ -6386,7 +6379,7 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
we're interested in the last element in x_3 for which a_2 || a_3
is true, whereas the current reduction chain handling would
- vectorize x_2 as a normal VEC_COND_EXPR and only treat x_3
+ vectorize x_2 as a normal VEC_COND_*_EXPR and only treat x_3
as a reduction operation. */
if (reduc_index == -1)
{
diff --git a/gcc/tree-vect-patterns.c b/gcc/tree-vect-patterns.c
index baa9a4cb8fa..402879c8635 100644
--- a/gcc/tree-vect-patterns.c
+++ b/gcc/tree-vect-patterns.c
@@ -3460,7 +3460,7 @@ check_bool_pattern (tree var, vec_info *vinfo, hash_set<gimple *> &stmts)
tree vecitype, comp_vectype;
/* If the comparison can throw, then is_gimple_condexpr will be
- false and we can't make a COND_EXPR/VEC_COND_EXPR out of it. */
+ false and we can't make a COND_EXPR/VEC_COND_*_EXPR out of it. */
if (stmt_could_throw_p (cfun, def_stmt))
return false;
@@ -3582,7 +3582,7 @@ adjust_bool_pattern (tree var, tree out_type,
S3' c_T = x2 CMP2 y2 ? a_T : 0;
S4' f_T = c_T;
- At least when VEC_COND_EXPR is implemented using masks
+ At least when VEC_COND_*_EXPR is implemented using masks
cond ? 1 : 0 is as expensive as cond ? var : 0, in both cases it
computes the comparison masks and ands it, in one case with
all ones vector, in the other case with a vector register.
diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c
index b1e97f85d96..25fbeb0345a 100644
--- a/gcc/tree-vect-stmts.c
+++ b/gcc/tree-vect-stmts.c
@@ -55,6 +55,7 @@ along with GCC; see the file COPYING3. If not see
#include "gimple-fold.h"
#include "regs.h"
#include "attribs.h"
+#include "print-tree.h"
/* For lang_hooks.types.type_for_mode. */
#include "langhooks.h"
@@ -6427,7 +6428,7 @@ enum scan_store_kind {
/* Whole vector left shift permutation with zero init. */
scan_store_kind_lshift_zero,
- /* Whole vector left shift permutation and VEC_COND_EXPR. */
+ /* Whole vector left shift permutation and VEC_COND_*_EXPR. */
scan_store_kind_lshift_cond
};
@@ -7095,8 +7096,8 @@ vectorizable_scan_store (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
? boolean_false_node : boolean_true_node);
tree new_temp2 = make_ssa_name (vectype);
- g = gimple_build_assign (new_temp2, VEC_COND_EXPR, vb.build (),
- new_temp, vec_oprnd1);
+ g = gimple_build_vec_cond_expr (new_temp2, vb.build (),
+ new_temp, vec_oprnd1);
new_stmt_info = vect_finish_stmt_generation (stmt_info, g, gsi);
STMT_VINFO_RELATED_STMT (prev_stmt_info) = new_stmt_info;
prev_stmt_info = new_stmt_info;
@@ -9769,7 +9770,7 @@ vect_is_simple_cond (tree cond, vec_info *vinfo,
Check if STMT_INFO is conditional modify expression that can be vectorized.
If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized
- stmt using VEC_COND_EXPR to replace it, put it in VEC_STMT, and insert it
+ stmt using VEC_COND_*_EXPR to replace it, put it in VEC_STMT, and insert it
at GSI.
When STMT_INFO is vectorized as a nested cycle, for_reduction is true.
@@ -10158,8 +10159,9 @@ vectorizable_condition (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
{
new_temp = make_ssa_name (vec_dest);
gassign *new_stmt
- = gimple_build_assign (new_temp, VEC_COND_EXPR, vec_compare,
- vec_then_clause, vec_else_clause);
+ = gimple_build_vec_cond_expr (new_temp, vec_compare,
+ vec_then_clause,
+ vec_else_clause);
new_stmt_info
= vect_finish_stmt_generation (stmt_info, new_stmt, gsi);
}
diff --git a/gcc/tree.def b/gcc/tree.def
index fb6e7344fa6..da9d28359fd 100644
--- a/gcc/tree.def
+++ b/gcc/tree.def
@@ -551,6 +551,13 @@ DEFTREECODE (VEC_SERIES_EXPR, "vec_series_expr", tcc_binary, 2)
*/
DEFTREECODE (VEC_COND_EXPR, "vec_cond_expr", tcc_expression, 3)
+DEFTREECODE (VEC_COND_LT_EXPR, "vec_cond_lt_expr", tcc_expression, 4)
+DEFTREECODE (VEC_COND_LE_EXPR, "vec_cond_le_expr", tcc_expression, 4)
+DEFTREECODE (VEC_COND_GT_EXPR, "vec_cond_gt_expr", tcc_expression, 4)
+DEFTREECODE (VEC_COND_GE_EXPR, "vec_cond_ge_expr", tcc_expression, 4)
+DEFTREECODE (VEC_COND_EQ_EXPR, "vec_cond_eq_expr", tcc_expression, 4)
+DEFTREECODE (VEC_COND_NE_EXPR, "vec_cond_ne_expr", tcc_expression, 4)
+
/* Vector permutation expression. A = VEC_PERM_EXPR<v0, v1, mask> means
N = length(mask)
diff --git a/gcc/tree.h b/gcc/tree.h
index c825109b5f7..27752932a31 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -5132,6 +5132,70 @@ complete_or_array_type_p (const_tree type)
&& COMPLETE_TYPE_P (TREE_TYPE (type)));
}
+static inline tree_code
+cmp_to_vec_cmp_code (tree_code code)
+{
+ switch (code)
+ {
+ case LT_EXPR:
+ return VEC_COND_LT_EXPR;
+ case LE_EXPR:
+ return VEC_COND_LE_EXPR;
+ case GT_EXPR:
+ return VEC_COND_GT_EXPR;
+ case GE_EXPR:
+ return VEC_COND_GE_EXPR;
+ case EQ_EXPR:
+ return VEC_COND_EQ_EXPR;
+ case NE_EXPR:
+ return VEC_COND_NE_EXPR;
+ default:
+ gcc_unreachable ();
+ }
+}
+
+static inline tree_code
+vec_cmp_to_cmp_code (tree_code code)
+{
+ switch (code)
+ {
+ case VEC_COND_LT_EXPR:
+ return LT_EXPR;
+ case VEC_COND_LE_EXPR:
+ return LE_EXPR;
+ case VEC_COND_GT_EXPR:
+ return GT_EXPR;
+ case VEC_COND_GE_EXPR:
+ return GE_EXPR;
+ case VEC_COND_EQ_EXPR:
+ return EQ_EXPR;
+ case VEC_COND_NE_EXPR:
+ return NE_EXPR;
+ default:
+ gcc_unreachable ();
+ }
+}
+
+#define CASE_VEC_COND_EXPR \
+ case VEC_COND_LT_EXPR: \
+ case VEC_COND_LE_EXPR: \
+ case VEC_COND_GT_EXPR: \
+ case VEC_COND_GE_EXPR: \
+ case VEC_COND_EQ_EXPR: \
+ case VEC_COND_NE_EXPR
+
+static inline bool
+vec_cond_expr_p (tree_code code)
+{
+ switch (code)
+ {
+ CASE_VEC_COND_EXPR:
+ return true;
+ default:
+ return false;
+ }
+}
+
/* Return true if the value of T could be represented as a poly_widest_int. */
inline bool
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment