From patchwork Tue Mar 19 08:06:13 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marc Glisse X-Patchwork-Id: 228951 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "localhost", Issuer "www.qmailtoaster.com" (not verified)) by ozlabs.org (Postfix) with ESMTPS id 0979C2C00AD for ; Tue, 19 Mar 2013 19:50:34 +1100 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:cc:subject:in-reply-to:message-id:references :mime-version:content-type; q=dns; s=dkim1; b=vXKztaSlGwEaiurCqs CRgzLjKYbnO11F6OX94Akcd1q8+RfQBn42GC+0lTJn23Af0blNBhNTsGwzJDZ6K/ DAb9TDnbZKhLAI3PAHBNpDnZnjEeyuN+XBQVykulHw6zAUB4GnEo4co13yXIWmdw zOGdTjlTnIWoC6O6SnFV9bKt8= DKIM-Signature: v=1; a=rsa-sha1; c=simple; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:cc:subject:in-reply-to:message-id:references :mime-version:content-type; s=dkim1; bh=caXpegntzR5+m++Hy2OGhtGq X6s=; b=v6yFFv8wcVWSEVCVi6Gleyfrbht7QqetdrVew9xwRJa5I78OLbNzSCtB aFcNAlTIQAwkA2CIt6ecrgYiKTG8EFyQCsSTdI4zG9isQmONgSBIQG9R33d99TJ9 /coCtMBeocGhg5ZOwkGUDbH8sfqHtzGTdk7LJv2MSN4tjWmz0eI= Received: (qmail 12349 invoked by alias); 19 Mar 2013 08:24:35 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 8834 invoked by uid 89); 19 Mar 2013 08:06:15 -0000 Received: from mail3-relais-sop.national.inria.fr (HELO mail3-relais-sop.national.inria.fr) (192.134.164.104) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 19 Mar 2013 08:06:15 +0000 Received: from stedding.saclay.inria.fr ([193.55.250.194]) by mail3-relais-sop.national.inria.fr with ESMTP/TLS/DHE-RSA-AES128-SHA; 19 Mar 2013 09:06:13 +0100 Received: from glisse (helo=localhost) by stedding.saclay.inria.fr with local-esmtp (Exim 4.80) (envelope-from ) id 1UHrYj-0008U2-KX; Tue, 19 Mar 2013 09:06:13 +0100 Date: Tue, 19 Mar 2013 09:06:13 +0100 (CET) From: Marc Glisse To: gcc-patches@gcc.gnu.org cc: Richard Biener Subject: Re: Fold VEC_COND_EXPR to abs, min, max In-Reply-To: Message-ID: References: User-Agent: Alpine 2.02 (DEB 1266 2009-07-14) MIME-Version: 1.0 Hello, new version of the patch. Note that for the simplification from {-1,-1}?a:b to a, I removed the test that b has no side effects and call pedantic_omit_one_operand_loc instead. Bootstrap + testsuite on x86_64-linux-gnu. 2013-03-19 Marc Glisse gcc/ * tree.h (VECTOR_TYPE_P): New macro. (VECTOR_INTEGER_TYPE_P, VECTOR_FLOAT_TYPE_P, FLOAT_TYPE_P, TYPE_MODE): Use it. * fold-const.c (fold_cond_expr_with_comparison): Use build_zero_cst. VEC_COND_EXPR cannot be lvalues. (fold_ternary_loc) : Merge with the COND_EXPR case. gcc/cp/ * call.c (build_conditional_expr_1): Fold VEC_COND_EXPR. gcc/testsuite/ * g++.dg/ext/vector21.C: New testcase. Index: gcc/testsuite/g++.dg/ext/vector21.C =================================================================== --- gcc/testsuite/g++.dg/ext/vector21.C (revision 0) +++ gcc/testsuite/g++.dg/ext/vector21.C (revision 0) @@ -0,0 +1,39 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-gimple" } */ + +typedef int vec __attribute__ ((vector_size (4 * sizeof (int)))); + +void f1 (vec *x) +{ + *x = (*x >= 0) ? *x : -*x; +} +void f2 (vec *x) +{ + *x = (0 < *x) ? *x : -*x; +} +void g1 (vec *x) +{ + *x = (*x < 0) ? -*x : *x; +} +void g2 (vec *x) +{ + *x = (0 > *x) ? -*x : *x; +} +void h (vec *x, vec *y) +{ + *x = (*x < *y) ? *y : *x; +} +void i (vec *x, vec *y) +{ + *x = (*x < *y) ? *x : *y; +} +void j (vec *x, vec *y) +{ + *x = (*x < *y) ? *x : *x; +} + +/* { dg-final { scan-tree-dump-times "ABS_EXPR" 4 "gimple" } } */ +/* { dg-final { scan-tree-dump "MIN_EXPR" "gimple" } } */ +/* { dg-final { scan-tree-dump "MAX_EXPR" "gimple" } } */ +/* { dg-final { scan-tree-dump-not "VEC_COND_EXPR" "gimple" } } */ +/* { dg-final { cleanup-tree-dump "gimple" } } */ Property changes on: gcc/testsuite/g++.dg/ext/vector21.C ___________________________________________________________________ Added: svn:eol-style + native Added: svn:keywords + Author Date Id Revision URL Index: gcc/cp/call.c =================================================================== --- gcc/cp/call.c (revision 196748) +++ gcc/cp/call.c (working copy) @@ -4430,23 +4430,23 @@ build_conditional_expr_1 (tree arg1, tre || TYPE_SIZE (arg1_type) != TYPE_SIZE (arg2_type)) { if (complain & tf_error) error ("incompatible vector types in conditional expression: " "%qT, %qT and %qT", TREE_TYPE (arg1), TREE_TYPE (orig_arg2), TREE_TYPE (orig_arg3)); return error_mark_node; } if (!COMPARISON_CLASS_P (arg1)) - arg1 = build2 (NE_EXPR, signed_type_for (arg1_type), arg1, + arg1 = fold_build2 (NE_EXPR, signed_type_for (arg1_type), arg1, build_zero_cst (arg1_type)); - return build3 (VEC_COND_EXPR, arg2_type, arg1, arg2, arg3); + return fold_build3 (VEC_COND_EXPR, arg2_type, arg1, arg2, arg3); } /* [expr.cond] The first expression is implicitly converted to bool (clause _conv_). */ arg1 = perform_implicit_conversion_flags (boolean_type_node, arg1, complain, LOOKUP_NORMAL); if (error_operand_p (arg1)) return error_mark_node; Index: gcc/tree.h =================================================================== --- gcc/tree.h (revision 196748) +++ gcc/tree.h (working copy) @@ -974,20 +974,24 @@ extern void omp_clause_range_check_faile && (TREE_TYPE (EXP) \ == TREE_TYPE (TREE_OPERAND (EXP, 0)))) \ (EXP) = TREE_OPERAND (EXP, 0) /* Remove unnecessary type conversions according to tree_ssa_useless_type_conversion. */ #define STRIP_USELESS_TYPE_CONVERSION(EXP) \ (EXP) = tree_ssa_strip_useless_type_conversions (EXP) +/* Nonzero if TYPE represents a vector type. */ + +#define VECTOR_TYPE_P(TYPE) (TREE_CODE (TYPE) == VECTOR_TYPE) + /* Nonzero if TYPE represents an integral type. Note that we do not include COMPLEX types here. Keep these checks in ascending code order. */ #define INTEGRAL_TYPE_P(TYPE) \ (TREE_CODE (TYPE) == ENUMERAL_TYPE \ || TREE_CODE (TYPE) == BOOLEAN_TYPE \ || TREE_CODE (TYPE) == INTEGER_TYPE) /* Nonzero if TYPE represents a non-saturating fixed-point type. */ @@ -1009,39 +1013,39 @@ extern void omp_clause_range_check_faile #define SCALAR_FLOAT_TYPE_P(TYPE) (TREE_CODE (TYPE) == REAL_TYPE) /* Nonzero if TYPE represents a complex floating-point type. */ #define COMPLEX_FLOAT_TYPE_P(TYPE) \ (TREE_CODE (TYPE) == COMPLEX_TYPE \ && TREE_CODE (TREE_TYPE (TYPE)) == REAL_TYPE) /* Nonzero if TYPE represents a vector integer type. */ -#define VECTOR_INTEGER_TYPE_P(TYPE) \ - (TREE_CODE (TYPE) == VECTOR_TYPE \ - && TREE_CODE (TREE_TYPE (TYPE)) == INTEGER_TYPE) +#define VECTOR_INTEGER_TYPE_P(TYPE) \ + (VECTOR_TYPE_P (TYPE) \ + && TREE_CODE (TREE_TYPE (TYPE)) == INTEGER_TYPE) /* Nonzero if TYPE represents a vector floating-point type. */ #define VECTOR_FLOAT_TYPE_P(TYPE) \ - (TREE_CODE (TYPE) == VECTOR_TYPE \ + (VECTOR_TYPE_P (TYPE) \ && TREE_CODE (TREE_TYPE (TYPE)) == REAL_TYPE) /* Nonzero if TYPE represents a floating-point type, including complex and vector floating-point types. The vector and complex check does not use the previous two macros to enable early folding. */ #define FLOAT_TYPE_P(TYPE) \ (SCALAR_FLOAT_TYPE_P (TYPE) \ || ((TREE_CODE (TYPE) == COMPLEX_TYPE \ - || TREE_CODE (TYPE) == VECTOR_TYPE) \ + || VECTOR_TYPE_P (TYPE)) \ && SCALAR_FLOAT_TYPE_P (TREE_TYPE (TYPE)))) /* Nonzero if TYPE represents a decimal floating-point type. */ #define DECIMAL_FLOAT_TYPE_P(TYPE) \ (SCALAR_FLOAT_TYPE_P (TYPE) \ && DECIMAL_FLOAT_MODE_P (TYPE_MODE (TYPE))) /* Nonzero if TYPE is a record or union type. */ #define RECORD_OR_UNION_TYPE_P(TYPE) \ (TREE_CODE (TYPE) == RECORD_TYPE \ @@ -2109,21 +2113,21 @@ struct GTY(()) tree_block { #define TYPE_REFERENCE_TO(NODE) (TYPE_CHECK (NODE)->type_common.reference_to) #define TYPE_PRECISION(NODE) (TYPE_CHECK (NODE)->type_common.precision) #define TYPE_NAME(NODE) (TYPE_CHECK (NODE)->type_common.name) #define TYPE_NEXT_VARIANT(NODE) (TYPE_CHECK (NODE)->type_common.next_variant) #define TYPE_MAIN_VARIANT(NODE) (TYPE_CHECK (NODE)->type_common.main_variant) #define TYPE_CONTEXT(NODE) (TYPE_CHECK (NODE)->type_common.context) /* Vector types need to check target flags to determine type. */ extern enum machine_mode vector_type_mode (const_tree); #define TYPE_MODE(NODE) \ - (TREE_CODE (TYPE_CHECK (NODE)) == VECTOR_TYPE \ + (VECTOR_TYPE_P (TYPE_CHECK (NODE)) \ ? vector_type_mode (NODE) : (NODE)->type_common.mode) #define SET_TYPE_MODE(NODE, MODE) \ (TYPE_CHECK (NODE)->type_common.mode = (MODE)) /* The "canonical" type for this type node, which is used by frontends to compare the type for equality with another type. If two types are equal (based on the semantics of the language), then they will have equivalent TYPE_CANONICAL entries. As a special case, if TYPE_CANONICAL is NULL_TREE, and thus Index: gcc/fold-const.c =================================================================== --- gcc/fold-const.c (revision 196748) +++ gcc/fold-const.c (working copy) @@ -4625,21 +4625,21 @@ fold_cond_expr_with_comparison (location A == 0 ? A : 0 is always 0 unless A is -0. Note that both transformations are correct when A is NaN: A != 0 is then true, and A == 0 is false. */ if (!HONOR_SIGNED_ZEROS (TYPE_MODE (type)) && integer_zerop (arg01) && integer_zerop (arg2)) { if (comp_code == NE_EXPR) return pedantic_non_lvalue_loc (loc, fold_convert_loc (loc, type, arg1)); else if (comp_code == EQ_EXPR) - return build_int_cst (type, 0); + return build_zero_cst (type); } /* Try some transformations of A op B ? A : B. A == B? A : B same as B A != B? A : B same as A A >= B? A : B same as max (A, B) A > B? A : B same as max (B, A) A <= B? A : B same as min (A, B) A < B? A : B same as min (B, A) @@ -4659,20 +4659,21 @@ fold_cond_expr_with_comparison (location The conversions to max() and min() are not correct if B is a number and A is not. The conditions in the original expressions will be false, so all four give B. The min() and max() versions would give a NaN instead. */ if (!HONOR_SIGNED_ZEROS (TYPE_MODE (type)) && operand_equal_for_comparison_p (arg01, arg2, arg00) /* Avoid these transformations if the COND_EXPR may be used as an lvalue in the C++ front-end. PR c++/19199. */ && (in_gimple_form + || VECTOR_TYPE_P (type) || (strcmp (lang_hooks.name, "GNU C++") != 0 && strcmp (lang_hooks.name, "GNU Objective-C++") != 0) || ! maybe_lvalue_p (arg1) || ! maybe_lvalue_p (arg2))) { tree comp_op0 = arg00; tree comp_op1 = arg01; tree comp_type = TREE_TYPE (comp_op0); /* Avoid adding NOP_EXPRs in case this is an lvalue. */ @@ -13891,37 +13892,46 @@ fold_ternary_loc (location_t loc, enum t { unsigned HOST_WIDE_INT idx; tree field, value; FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (arg0), idx, field, value) if (field == arg1) return value; } return NULL_TREE; case COND_EXPR: + case VEC_COND_EXPR: /* Pedantic ANSI C says that a conditional expression is never an lvalue, so all simple results must be passed through pedantic_non_lvalue. */ if (TREE_CODE (arg0) == INTEGER_CST) { tree unused_op = integer_zerop (arg0) ? op1 : op2; tem = integer_zerop (arg0) ? op2 : op1; /* Only optimize constant conditions when the selected branch has the same type as the COND_EXPR. This avoids optimizing away "c ? x : throw", where the throw has a void type. Avoid throwing away that operand which contains label. */ if ((!TREE_SIDE_EFFECTS (unused_op) || !contains_label_p (unused_op)) && (! VOID_TYPE_P (TREE_TYPE (tem)) || VOID_TYPE_P (type))) return pedantic_non_lvalue_loc (loc, tem); return NULL_TREE; } + else if (TREE_CODE (arg0) == VECTOR_CST) + { + if (integer_all_onesp (arg0)) + return pedantic_omit_one_operand_loc (loc, type, arg1, arg2); + if (integer_zerop (arg0)) + return pedantic_omit_one_operand_loc (loc, type, arg2, arg1); + } + if (operand_equal_p (arg1, op2, 0)) return pedantic_omit_one_operand_loc (loc, type, arg1, arg0); /* If we have A op B ? A : C, we may be able to convert this to a simpler expression, depending on the operation and the values of B and C. Signed zeros prevent all of these transformations, for reasons given above each one. Also try swapping the arguments and inverting the conditional. */ if (COMPARISON_CLASS_P (arg0) @@ -13943,20 +13953,24 @@ fold_ternary_loc (location_t loc, enum t location_t loc0 = expr_location_or (arg0, loc); tem = fold_truth_not_expr (loc0, arg0); if (tem && COMPARISON_CLASS_P (tem)) { tem = fold_cond_expr_with_comparison (loc, type, tem, op2, op1); if (tem) return tem; } } + /* ??? Fixup the code below for VEC_COND_EXPR. */ + if (code == VEC_COND_EXPR) + return NULL_TREE; + /* If the second operand is simpler than the third, swap them since that produces better jump optimization results. */ if (truth_value_p (TREE_CODE (arg0)) && tree_swap_operands_p (op1, op2, false)) { location_t loc0 = expr_location_or (arg0, loc); /* See if this can be inverted. If it can't, possibly because it was a floating-point inequality comparison, don't do anything. */ tem = fold_truth_not_expr (loc0, arg0); @@ -14130,30 +14144,20 @@ fold_ternary_loc (location_t loc, enum t /* Convert A ? 1 : B into A || B if A and B are truth values. */ if (integer_onep (arg1) && truth_value_p (TREE_CODE (arg0)) && truth_value_p (TREE_CODE (op2))) return fold_build2_loc (loc, TRUTH_ORIF_EXPR, type, fold_convert_loc (loc, type, arg0), op2); return NULL_TREE; - case VEC_COND_EXPR: - if (TREE_CODE (arg0) == VECTOR_CST) - { - if (integer_all_onesp (arg0) && !TREE_SIDE_EFFECTS (op2)) - return pedantic_non_lvalue_loc (loc, op1); - if (integer_zerop (arg0) && !TREE_SIDE_EFFECTS (op1)) - return pedantic_non_lvalue_loc (loc, op2); - } - return NULL_TREE; - case CALL_EXPR: /* CALL_EXPRs used to be ternary exprs. Catch any mistaken uses of fold_ternary on them. */ gcc_unreachable (); case BIT_FIELD_REF: if ((TREE_CODE (arg0) == VECTOR_CST || (TREE_CODE (arg0) == CONSTRUCTOR && TREE_CODE (TREE_TYPE (arg0)) == VECTOR_TYPE)) && (type == TREE_TYPE (TREE_TYPE (arg0))