Hello,
I have been experimenting with generating VEC_COND_EXPR from the
front-end, and these are just a couple things I noticed.
1) optabs.c requires that the first argument of vec_cond_expr be a
comparison, but verify_gimple_assign_ternary only checks
is_gimple_condexpr, like for COND_EXPR. In the long term, it seems better
to also allow ssa_name and vector_cst (thus match the is_gimple_condexpr
condition), but for now I just want to know early if I created an invalid
vec_cond_expr.
2) a little refactoring of the code to find a suitable vector type for
comparison results, and one more place where it should be used (no
testcase yet because I don't know if that path can be taken without
front-end changes first). I did wonder, for tree-ssa-forwprop, about using
directly TREE_TYPE (cond) without truth_type_for.
Hmm, now I am wondering whether I should have waited until I had front-end
vec_cond_expr support to submit everything at once...
2012-09-27 Marc Glisse <[email protected]>
* tree-cfg.c (verify_gimple_assign_ternary): Stricter check on
first argument of VEC_COND_EXPR.
* tree.c (truth_type_for): New function.
* tree.h (truth_type_for): Declare.
* gimple-fold.c (and_comparisons_1): Call it.
(or_comparisons_1): Likewise.
* tree-ssa-forwprop.c (forward_propagate_into_cond): Likewise.
--
Marc GlisseIndex: gcc/tree-ssa-forwprop.c
===================================================================
--- gcc/tree-ssa-forwprop.c (revision 191810)
+++ gcc/tree-ssa-forwprop.c (working copy)
@@ -549,21 +549,22 @@ static bool
forward_propagate_into_cond (gimple_stmt_iterator *gsi_p)
{
gimple stmt = gsi_stmt (*gsi_p);
tree tmp = NULL_TREE;
tree cond = gimple_assign_rhs1 (stmt);
bool swap = false;
/* We can do tree combining on SSA_NAME and comparison expressions. */
if (COMPARISON_CLASS_P (cond))
tmp = forward_propagate_into_comparison_1 (stmt, TREE_CODE (cond),
- boolean_type_node,
+ truth_type_for
+ (TREE_TYPE (cond)),
TREE_OPERAND (cond, 0),
TREE_OPERAND (cond, 1));
else if (TREE_CODE (cond) == SSA_NAME)
{
enum tree_code code;
tree name = cond;
gimple def_stmt = get_prop_source_stmt (name, true, NULL);
if (!def_stmt || !can_propagate_from (def_stmt))
return 0;
Index: gcc/tree-cfg.c
===================================================================
--- gcc/tree-cfg.c (revision 191810)
+++ gcc/tree-cfg.c (working copy)
@@ -3758,22 +3758,24 @@ verify_gimple_assign_ternary (gimple stm
tree rhs2_type = TREE_TYPE (rhs2);
tree rhs3 = gimple_assign_rhs3 (stmt);
tree rhs3_type = TREE_TYPE (rhs3);
if (!is_gimple_reg (lhs))
{
error ("non-register as LHS of ternary operation");
return true;
}
- if (((rhs_code == VEC_COND_EXPR || rhs_code == COND_EXPR)
- ? !is_gimple_condexpr (rhs1) : !is_gimple_val (rhs1))
+ if (((rhs_code == COND_EXPR) ? !is_gimple_condexpr (rhs1)
+ : (rhs_code == VEC_COND_EXPR) ? (!is_gimple_condexpr (rhs1)
+ || is_gimple_val (rhs1))
+ : !is_gimple_val (rhs1))
|| !is_gimple_val (rhs2)
|| !is_gimple_val (rhs3))
{
error ("invalid operands in ternary operation");
return true;
}
/* First handle operations that involve different types. */
switch (rhs_code)
{
Index: gcc/gimple-fold.c
===================================================================
--- gcc/gimple-fold.c (revision 191810)
+++ gcc/gimple-fold.c (working copy)
@@ -23,21 +23,20 @@ along with GCC; see the file COPYING3.
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
#include "flags.h"
#include "function.h"
#include "dumpfile.h"
#include "tree-flow.h"
#include "tree-ssa-propagate.h"
#include "target.h"
#include "gimple-fold.h"
-#include "langhooks.h"
/* Return true when DECL can be referenced from current unit.
FROM_DECL (if non-null) specify constructor of variable DECL was taken from.
We can get declarations that are not possible to reference for various
reasons:
1) When analyzing C++ virtual tables.
C++ virtual tables do have known constructors even
when they are keyed to other compilation unit.
Those tables can contain pointers to methods and vars
@@ -1686,29 +1685,21 @@ and_var_with_comparison_1 (gimple stmt,
(OP1A CODE1 OP1B) and (OP2A CODE2 OP2B), respectively.
If this can be done without constructing an intermediate value,
return the resulting tree; otherwise NULL_TREE is returned.
This function is deliberately asymmetric as it recurses on SSA_DEFs
in the first comparison but not the second. */
static tree
and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
enum tree_code code2, tree op2a, tree op2b)
{
- tree truth_type = boolean_type_node;
- if (TREE_CODE (TREE_TYPE (op1a)) == VECTOR_TYPE)
- {
- tree vec_type = TREE_TYPE (op1a);
- tree elem = lang_hooks.types.type_for_size
- (GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (vec_type))), 0);
- truth_type = build_opaque_vector_type (elem,
- TYPE_VECTOR_SUBPARTS (vec_type));
- }
+ tree truth_type = truth_type_for (TREE_TYPE (op1a));
/* First check for ((x CODE1 y) AND (x CODE2 y)). */
if (operand_equal_p (op1a, op2a, 0)
&& operand_equal_p (op1b, op2b, 0))
{
/* Result will be either NULL_TREE, or a combined comparison. */
tree t = combine_comparisons (UNKNOWN_LOCATION,
TRUTH_ANDIF_EXPR, code1, code2,
truth_type, op1a, op1b);
if (t)
@@ -2158,29 +2149,21 @@ or_var_with_comparison_1 (gimple stmt,
(OP1A CODE1 OP1B) and (OP2A CODE2 OP2B), respectively.
If this can be done without constructing an intermediate value,
return the resulting tree; otherwise NULL_TREE is returned.
This function is deliberately asymmetric as it recurses on SSA_DEFs
in the first comparison but not the second. */
static tree
or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
enum tree_code code2, tree op2a, tree op2b)
{
- tree truth_type = boolean_type_node;
- if (TREE_CODE (TREE_TYPE (op1a)) == VECTOR_TYPE)
- {
- tree vec_type = TREE_TYPE (op1a);
- tree elem = lang_hooks.types.type_for_size
- (GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (vec_type))), 0);
- truth_type = build_opaque_vector_type (elem,
- TYPE_VECTOR_SUBPARTS (vec_type));
- }
+ tree truth_type = truth_type_for (TREE_TYPE (op1a));
/* First check for ((x CODE1 y) OR (x CODE2 y)). */
if (operand_equal_p (op1a, op2a, 0)
&& operand_equal_p (op1b, op2b, 0))
{
/* Result will be either NULL_TREE, or a combined comparison. */
tree t = combine_comparisons (UNKNOWN_LOCATION,
TRUTH_ORIF_EXPR, code1, code2,
truth_type, op1a, op1b);
if (t)
Index: gcc/tree.c
===================================================================
--- gcc/tree.c (revision 191810)
+++ gcc/tree.c (working copy)
@@ -10243,20 +10243,36 @@ unsigned_type_for (tree type)
/* If TYPE is an integral or pointer type, return an integer type with
the same precision which is signed, or itself if TYPE is already a
signed integer type. */
tree
signed_type_for (tree type)
{
return signed_or_unsigned_type_for (0, type);
}
+/* If TYPE is a vector type, return a signed integer vector type with the
+ same width and number of subparts. Otherwise return boolean_type_node. */
+
+tree
+truth_type_for (tree type)
+{
+ if (TREE_CODE (type) == VECTOR_TYPE)
+ {
+ tree elem = lang_hooks.types.type_for_size
+ (GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (type))), 0);
+ return build_opaque_vector_type (elem, TYPE_VECTOR_SUBPARTS (type));
+ }
+ else
+ return boolean_type_node;
+}
+
/* Returns the largest value obtainable by casting something in INNER type to
OUTER type. */
tree
upper_bound_in_type (tree outer, tree inner)
{
double_int high;
unsigned int det = 0;
unsigned oprec = TYPE_PRECISION (outer);
unsigned iprec = TYPE_PRECISION (inner);
Index: gcc/tree.h
===================================================================
--- gcc/tree.h (revision 191810)
+++ gcc/tree.h (working copy)
@@ -4762,20 +4762,21 @@ extern tree build_call_valist (tree, tre
extern tree build_call_array_loc (location_t, tree, tree, int, const tree *);
extern tree build_call_vec (tree, tree, VEC(tree,gc) *);
/* Construct various nodes representing data types. */
extern tree make_signed_type (int);
extern tree make_unsigned_type (int);
extern tree signed_or_unsigned_type_for (int, tree);
extern tree signed_type_for (tree);
extern tree unsigned_type_for (tree);
+extern tree truth_type_for (tree);
extern void initialize_sizetypes (void);
extern void fixup_unsigned_type (tree);
extern tree build_pointer_type_for_mode (tree, enum machine_mode, bool);
extern tree build_pointer_type (tree);
extern tree build_reference_type_for_mode (tree, enum machine_mode, bool);
extern tree build_reference_type (tree);
extern tree build_vector_type_for_mode (tree, enum machine_mode);
extern tree build_vector_type (tree innertype, int nunits);
extern tree build_opaque_vector_type (tree innertype, int nunits);
extern tree build_type_no_quals (tree);