From patchwork Wed May 8 22:55:37 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marc Glisse X-Patchwork-Id: 242660 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 2D0332C00F0 for ; Thu, 9 May 2013 08:55:49 +1000 (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:subject:message-id:mime-version:content-type; q=dns; s= default; b=ki2hhYVspnli8aIRj+xkODHUG4UeAomG02q9dNrf+3QeMqz7vrkXw VTzitg+L7Zr2kMlakR9HqVuLHTzdCZ+PQoWIj8zfEji4Z4319O/nSyH7QBu/jnfE 0g0ig8XKA2UyABxVrbG8/pVd3a0HuAiW4gRFLkt6jhAbgpsV7t6y+g= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; s= default; bh=Qi67LyRgvWfNwMsumGSlme0H4D0=; b=T5i2Z3pe8TrT4kPwk0ZS W1tTTI5Gkq4GWIcchKN3FnHKe8k0tkAaH0DKEKTVcZjnih7vsxGG09V66SY0V5qw bS+oOPCwz9uZGQmrIsMX8NiQwrMpDgf8UDim/t9ivF2GJnnkBolIDuOKtfit9usN gWw51i+HFSMIocnTGceGAtA= Received: (qmail 20989 invoked by alias); 8 May 2013 22:55:42 -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 20980 invoked by uid 89); 8 May 2013 22:55:42 -0000 X-Spam-SWARE-Status: No, score=-5.6 required=5.0 tests=AWL, BAYES_00, RP_MATCHES_RCVD autolearn=ham version=3.3.1 Received: from mail3-relais-sop.national.inria.fr (HELO mail3-relais-sop.national.inria.fr) (192.134.164.104) by sourceware.org (qpsmtpd/0.84/v0.84-167-ge50287c) with ESMTP; Wed, 08 May 2013 22:55:40 +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; 09 May 2013 00:55:37 +0200 Received: from glisse (helo=localhost) by stedding.saclay.inria.fr with local-esmtp (Exim 4.80) (envelope-from ) id 1UaDGr-0000bz-8h for gcc-patches@gcc.gnu.org; Thu, 09 May 2013 00:55:37 +0200 Date: Thu, 9 May 2013 00:55:37 +0200 (CEST) From: Marc Glisse To: gcc-patches@gcc.gnu.org Subject: More vector folding Message-ID: User-Agent: Alpine 2.02 (DEB 1266 2009-07-14) MIME-Version: 1.0 X-Virus-Found: No Hello, here are a few more changes to fold-const.c so vectors can use the existing optimizations. Note that I made fold_truth_not_expr safe for use with vector BIT_NOT_EXPR. Passes bootstrap+testsuite on x86_64-linux-gnu. 2013-05-09 Marc Glisse gcc/ * fold-const.c (fold_negate_expr): Handle vectors. (fold_truth_not_expr): Likewise. (invert_truthvalue_loc): Likewise. (fold_single_bit_test): Likewise. (fold_comparison): Likewise. (fold_ternary_loc): Likewise. gcc/testsuite/ * g++.dg/ext/vector22.C: New testcase. Index: gcc/testsuite/g++.dg/ext/vector22.C =================================================================== --- gcc/testsuite/g++.dg/ext/vector22.C (revision 0) +++ gcc/testsuite/g++.dg/ext/vector22.C (revision 0) @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-gimple" } */ + +typedef unsigned vec __attribute__((vector_size(4*sizeof(int)))); + +void f(vec*a,vec*b){ + *a=(*a)?-1:(*b<10); + *b=(*b)?(*a<10):0; +} +void g(vec*a,vec*b){ + *a=(*a)?(*a<*a):-1; + *b=(*b)?-1:(*b<*b); +} +void h(vec*a){ + *a=(~*a==5); +} + +/* { dg-final { scan-tree-dump-not "~" "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/vector22.C ___________________________________________________________________ Added: svn:eol-style + native Added: svn:keywords + Author Date Id Revision URL Index: gcc/fold-const.c =================================================================== --- gcc/fold-const.c (revision 198726) +++ gcc/fold-const.c (working copy) @@ -519,21 +519,21 @@ fold_negate_expr (location_t loc, tree t { tree type = TREE_TYPE (t); tree tem; switch (TREE_CODE (t)) { /* Convert - (~A) to A + 1. */ case BIT_NOT_EXPR: if (INTEGRAL_TYPE_P (type)) return fold_build2_loc (loc, PLUS_EXPR, type, TREE_OPERAND (t, 0), - build_int_cst (type, 1)); + build_one_cst (type)); break; case INTEGER_CST: tem = fold_negate_const (t, type); if (TREE_OVERFLOW (tem) == TREE_OVERFLOW (t) || !TYPE_OVERFLOW_TRAPS (type)) return tem; break; case REAL_CST: @@ -3110,20 +3110,23 @@ fold_truth_not_expr (location_t loc, tre return build2_loc (loc, code, type, TREE_OPERAND (arg, 0), TREE_OPERAND (arg, 1)); } switch (code) { case INTEGER_CST: return constant_boolean_node (integer_zerop (arg), type); + case VECTOR_CST: + return fold_unary_loc (loc, BIT_NOT_EXPR, type, arg); + case TRUTH_AND_EXPR: loc1 = expr_location_or (TREE_OPERAND (arg, 0), loc); loc2 = expr_location_or (TREE_OPERAND (arg, 1), loc); return build2_loc (loc, TRUTH_OR_EXPR, type, invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 0)), invert_truthvalue_loc (loc2, TREE_OPERAND (arg, 1))); case TRUTH_OR_EXPR: loc1 = expr_location_or (TREE_OPERAND (arg, 0), loc); loc2 = expr_location_or (TREE_OPERAND (arg, 1), loc); @@ -3195,26 +3198,28 @@ fold_truth_not_expr (location_t loc, tre return build1_loc (loc, TRUTH_NOT_EXPR, type, arg); /* ... fall through ... */ case FLOAT_EXPR: loc1 = expr_location_or (TREE_OPERAND (arg, 0), loc); return build1_loc (loc, TREE_CODE (arg), type, invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 0))); case BIT_AND_EXPR: - if (!integer_onep (TREE_OPERAND (arg, 1))) + if (VECTOR_TYPE_P (type) || !integer_onep (TREE_OPERAND (arg, 1))) return NULL_TREE; return build2_loc (loc, EQ_EXPR, type, arg, build_int_cst (type, 0)); case SAVE_EXPR: - return build1_loc (loc, TRUTH_NOT_EXPR, type, arg); + return build1_loc (loc, VECTOR_TYPE_P (type) ? BIT_NOT_EXPR + : TRUTH_NOT_EXPR, + type, arg); case CLEANUP_POINT_EXPR: loc1 = expr_location_or (TREE_OPERAND (arg, 0), loc); return build1_loc (loc, CLEANUP_POINT_EXPR, type, invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 0))); default: return NULL_TREE; } } @@ -3222,28 +3227,28 @@ fold_truth_not_expr (location_t loc, tre /* Return a simplified tree node for the truth-negation of ARG. This never alters ARG itself. We assume that ARG is an operation that returns a truth value (0 or 1). FIXME: one would think we would fold the result, but it causes problems with the dominator optimizer. */ tree invert_truthvalue_loc (location_t loc, tree arg) { - tree tem; - if (TREE_CODE (arg) == ERROR_MARK) return arg; - tem = fold_truth_not_expr (loc, arg); + tree tem = fold_truth_not_expr (loc, arg); + tree type = TREE_TYPE (arg); if (!tem) - tem = build1_loc (loc, TRUTH_NOT_EXPR, TREE_TYPE (arg), arg); + tem = build1_loc (loc, VECTOR_TYPE_P (type) ? BIT_NOT_EXPR : TRUTH_NOT_EXPR, + type, arg); return tem; } /* Given a bit-wise operation CODE applied to ARG0 and ARG1, see if both operands are another bit-wise operation with a common input. If so, distribute the bit operations to save an operation and possibly two if constants are involved. For example, convert (A | B) & (A | C) into A | (B & C) Further simplification will occur if B and C are constants. @@ -6602,21 +6607,21 @@ fold_single_bit_test (location_t loc, en signed_type = lang_hooks.types.type_for_mode (operand_mode, 0); unsigned_type = lang_hooks.types.type_for_mode (operand_mode, 1); intermediate_type = ops_unsigned ? unsigned_type : signed_type; inner = fold_convert_loc (loc, intermediate_type, inner); if (bitnum != 0) inner = build2 (RSHIFT_EXPR, intermediate_type, inner, size_int (bitnum)); - one = build_int_cst (intermediate_type, 1); + one = build_one_cst (intermediate_type); if (code == EQ_EXPR) inner = fold_build2_loc (loc, BIT_XOR_EXPR, intermediate_type, inner, one); /* Put the AND last so it can combine with more things. */ inner = build2 (BIT_AND_EXPR, intermediate_type, inner, one); /* Make sure to return the proper type. */ inner = fold_convert_loc (loc, result_type, inner); @@ -9578,21 +9583,21 @@ fold_comparison (location_t loc, enum tr { tree cmp_type = TREE_TYPE (TREE_OPERAND (arg0, 0)); return fold_build2_loc (loc, code, type, fold_convert_loc (loc, cmp_type, TREE_OPERAND (arg1, 0)), TREE_OPERAND (arg0, 0)); } /* Fold ~X op C as X op' ~C, where op' is the swapped comparison. */ if (TREE_CODE (arg0) == BIT_NOT_EXPR - && TREE_CODE (arg1) == INTEGER_CST) + && (TREE_CODE (arg1) == INTEGER_CST || TREE_CODE (arg1) == VECTOR_CST)) { tree cmp_type = TREE_TYPE (TREE_OPERAND (arg0, 0)); return fold_build2_loc (loc, swap_tree_comparison (code), type, TREE_OPERAND (arg0, 0), fold_build1_loc (loc, BIT_NOT_EXPR, cmp_type, fold_convert_loc (loc, cmp_type, arg1))); } return NULL_TREE; } @@ -14038,52 +14043,52 @@ 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); if (tem) return fold_build3_loc (loc, code, type, tem, op2, op1); } /* Convert A ? 1 : 0 to simply A. */ - if (integer_onep (op1) + if ((code == VEC_COND_EXPR ? integer_all_onesp (op1) + : (integer_onep (op1) + && !VECTOR_TYPE_P (type))) && integer_zerop (op2) /* If we try to convert OP0 to our type, the call to fold will try to move the conversion inside a COND, which will recurse. In that case, the COND_EXPR is probably the best choice, so leave it alone. */ && type == TREE_TYPE (arg0)) return pedantic_non_lvalue_loc (loc, arg0); /* Convert A ? 0 : 1 to !A. This prefers the use of NOT_EXPR over COND_EXPR in cases such as floating point comparisons. */ if (integer_zerop (op1) - && integer_onep (op2) + && (code == VEC_COND_EXPR ? integer_all_onesp (op2) + : (integer_onep (op2) + && !VECTOR_TYPE_P (type))) && truth_value_p (TREE_CODE (arg0))) return pedantic_non_lvalue_loc (loc, fold_convert_loc (loc, type, invert_truthvalue_loc (loc, arg0))); /* A < 0 ? : 0 is simply (A & ). */ if (TREE_CODE (arg0) == LT_EXPR && integer_zerop (TREE_OPERAND (arg0, 1)) && integer_zerop (op2) @@ -14186,60 +14191,67 @@ fold_ternary_loc (location_t loc, enum t && TREE_CODE (TREE_OPERAND (arg0, 0)) == BIT_AND_EXPR && operand_equal_p (TREE_OPERAND (TREE_OPERAND (arg0, 0), 1), arg1, OEP_ONLY_CONST)) return pedantic_non_lvalue_loc (loc, fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0))); /* Convert A ? B : 0 into A && B if A and B are truth values. */ if (integer_zerop (op2) && truth_value_p (TREE_CODE (arg0)) - && truth_value_p (TREE_CODE (arg1))) - return fold_build2_loc (loc, TRUTH_ANDIF_EXPR, type, - fold_convert_loc (loc, type, arg0), - arg1); + && truth_value_p (TREE_CODE (arg1)) + && (code == VEC_COND_EXPR || !VECTOR_TYPE_P (type))) + return fold_build2_loc (loc, code == VEC_COND_EXPR ? BIT_AND_EXPR + : TRUTH_ANDIF_EXPR, + type, fold_convert_loc (loc, type, arg0), arg1); /* Convert A ? B : 1 into !A || B if A and B are truth values. */ - if (integer_onep (op2) + if (code == VEC_COND_EXPR ? integer_all_onesp (op2) : integer_onep (op2) && truth_value_p (TREE_CODE (arg0)) - && truth_value_p (TREE_CODE (arg1))) + && truth_value_p (TREE_CODE (arg1)) + && (code == VEC_COND_EXPR || !VECTOR_TYPE_P (type))) { location_t loc0 = expr_location_or (arg0, loc); /* Only perform transformation if ARG0 is easily inverted. */ tem = fold_truth_not_expr (loc0, arg0); if (tem) - return fold_build2_loc (loc, TRUTH_ORIF_EXPR, type, - fold_convert_loc (loc, type, tem), - arg1); + return fold_build2_loc (loc, code == VEC_COND_EXPR + ? BIT_IOR_EXPR + : TRUTH_ORIF_EXPR, + type, fold_convert_loc (loc, type, tem), + arg1); } /* Convert A ? 0 : B into !A && B if A and B are truth values. */ if (integer_zerop (arg1) && truth_value_p (TREE_CODE (arg0)) - && truth_value_p (TREE_CODE (op2))) + && truth_value_p (TREE_CODE (op2)) + && (code == VEC_COND_EXPR || !VECTOR_TYPE_P (type))) { location_t loc0 = expr_location_or (arg0, loc); /* Only perform transformation if ARG0 is easily inverted. */ tem = fold_truth_not_expr (loc0, arg0); if (tem) - return fold_build2_loc (loc, TRUTH_ANDIF_EXPR, type, - fold_convert_loc (loc, type, tem), - op2); + return fold_build2_loc (loc, code == VEC_COND_EXPR + ? BIT_AND_EXPR : TRUTH_ANDIF_EXPR, + type, fold_convert_loc (loc, type, tem), + op2); } /* Convert A ? 1 : B into A || B if A and B are truth values. */ - if (integer_onep (arg1) + if (code == VEC_COND_EXPR ? integer_all_onesp (arg1) : 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); + && truth_value_p (TREE_CODE (op2)) + && (code == VEC_COND_EXPR || !VECTOR_TYPE_P (type))) + return fold_build2_loc (loc, code == VEC_COND_EXPR + ? BIT_IOR_EXPR : TRUTH_ORIF_EXPR, + type, fold_convert_loc (loc, type, arg0), 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