From patchwork Thu Aug 28 13:47:03 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Biener X-Patchwork-Id: 383841 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.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 0D6A914011E for ; Thu, 28 Aug 2014 23:54:08 +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=Paf64k1oAV2Ju//bXR8hyqHeVNnEmgcKGFs4AbwdQBFWrG4oBdKyq yfmIFYGQ9k30CbOAsE8prd3H8AixsSxhDP1ZTJ7CHzvIrdpWLPqw9rIUmvCbyQnJ yXtj1M8McLi3WVzeLDNj0iVpldHXDbz64VY9QYL+aOuRHPh8EbnZ3c= 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=85rDu/rm+S5St0QcPGM6nxchgvc=; b=kuVSlJRpIY9IY7+U5t6G Qbq0MrVLRuPZleBf7NGc2Fx0bznFovQNvdnrOxCyc78pLwXnX+iQOISI/YZQKG3E CeOevf3f/IDz6l0yW1hDtBVJ0wNnPDE8TTklSQAJxS15dXewUvnPf4I8NVGLSSrC 32sRMi2R2Fm3mqZcGOqpHO4= Received: (qmail 21852 invoked by alias); 28 Aug 2014 13:50:31 -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 21828 invoked by uid 89); 28 Aug 2014 13:50:30 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-3.3 required=5.0 tests=AWL, BAYES_00, RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-HELO: mx2.suse.de Received: from cantor2.suse.de (HELO mx2.suse.de) (195.135.220.15) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (CAMELLIA256-SHA encrypted) ESMTPS; Thu, 28 Aug 2014 13:50:27 +0000 Received: from relay1.suse.de (charybdis-ext.suse.de [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id 897D7ACCC for ; Thu, 28 Aug 2014 13:50:24 +0000 (UTC) Date: Thu, 28 Aug 2014 15:47:03 +0200 (CEST) From: Richard Biener To: gcc-patches@gcc.gnu.org Subject: [PATCH][match-and-simplify] Move simplify first in fold_stmt Message-ID: User-Agent: Alpine 2.11 (LSU 23 2013-08-11) MIME-Version: 1.0 Now as the fold_stmt re-org is merged from trunk this moves the simplify dispatch first before doing the legacy stuff. It also adds dumping to this place and removes dumping from tree-ssa-forwprop.c (as there it catches all fold_stmt transforms done). I now also dump the associated sequence which makes two match testcases fail (I've yet to investigate how to best write multi-line matching regexps in tcl...). The patch also adds more foldings from builtins.c and splits the match-1.c testcase. Committed. Richard. 2014-08-28 Richard Biener * gimple-fold.c (fold_stmt_1): Move gimple_simplify dispatch first, add dumping here. * tree-ssa-forwprop.c (pass_forwprop::execute): Remove dumping. * match-builtin.pd: Implement more patterns and fix existing ones. testsuite/ * gcc.dg/tree-ssa/match-1.c: Split into ... * gcc.dg/tree-ssa/match-builtins.c: ... this ... * tree-ssa/match-builtins-fast-math.c: ... and this. Index: gcc/gimple-fold.c =================================================================== --- gcc/gimple-fold.c (revision 214676) +++ gcc/gimple-fold.c (working copy) @@ -2876,6 +2876,71 @@ fold_stmt_1 (gimple_stmt_iterator *gsi, default:; } + /* Dispatch to pattern-based folding. */ + /* ??? Change "inplace" semantics to allow replacing a stmt if + no further stmts need to be inserted (basically disallow + creating of new SSA names). */ + if (!inplace + || is_gimple_assign (stmt)) + { + gimple_seq seq = NULL; + code_helper rcode; + tree ops[3] = {}; + if (gimple_simplify (stmt, &rcode, ops, inplace ? NULL : &seq, valueize)) + { + if (is_gimple_assign (stmt) + && rcode.is_tree_code ()) + { + if ((!inplace + || gimple_num_ops (stmt) <= get_gimple_rhs_num_ops (rcode)) + /* Play safe and do not allow abnormals to be mentioned in + newly created statements. */ + && !((TREE_CODE (ops[0]) == SSA_NAME + && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[0])) + || (ops[1] + && TREE_CODE (ops[1]) == SSA_NAME + && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[1])) + || (ops[2] + && TREE_CODE (ops[2]) == SSA_NAME + && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[2])))) + { + gimple_assign_set_rhs_with_ops_1 (gsi, rcode, + ops[0], ops[1], ops[2]); + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "gimple_simplified to "); + if (!gimple_seq_empty_p (seq)) + print_gimple_seq (dump_file, seq, 0, TDF_SLIM); + print_gimple_stmt (dump_file, gsi_stmt (*gsi), + 0, TDF_SLIM); + } + gsi_insert_seq_before (gsi, seq, GSI_SAME_STMT); + changed = true; + } + } + else if (!inplace) + { + if (gimple_has_lhs (stmt)) + { + tree lhs = gimple_get_lhs (stmt); + maybe_push_res_to_seq (rcode, TREE_TYPE (lhs), + ops, &seq, lhs); + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "gimple_simplified to "); + print_gimple_seq (dump_file, seq, 0, TDF_SLIM); + } + gsi_replace_with_seq_vops (gsi, seq); + changed = true; + } + else + gcc_unreachable (); + } + } + } + + stmt = gsi_stmt (*gsi); + /* Fold the main computation performed by the statement. */ switch (gimple_code (stmt)) { @@ -3012,58 +3077,7 @@ fold_stmt_1 (gimple_stmt_iterator *gsi, } } - /* Dispatch to pattern-based folding. - ??? Do this after the previous stuff as fold_stmt is used to make - stmts valid gimple again via maybe_fold_reference of ops. */ - /* ??? Change "inplace" semantics to allow replacing a stmt if - no further stmts need to be inserted (basically disallow - creating of new SSA names). */ - if (inplace - && !is_gimple_assign (stmt)) - return changed; - - gimple_seq seq = NULL; - code_helper rcode; - tree ops[3] = {}; - if (!gimple_simplify (stmt, &rcode, ops, inplace ? NULL : &seq, valueize)) - return changed; - - if (is_gimple_assign (stmt) - && rcode.is_tree_code ()) - { - if (inplace - && gimple_num_ops (stmt) <= get_gimple_rhs_num_ops (rcode)) - return changed; - /* Play safe and do not allow abnormals to be mentioned in - newly created statements. */ - if ((TREE_CODE (ops[0]) == SSA_NAME - && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[0])) - || (ops[1] - && TREE_CODE (ops[1]) == SSA_NAME - && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[1])) - || (ops[2] - && TREE_CODE (ops[2]) == SSA_NAME - && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[2]))) - return changed; - gimple_assign_set_rhs_with_ops_1 (gsi, rcode, ops[0], ops[1], ops[2]); - gsi_insert_seq_before (gsi, seq, GSI_SAME_STMT); - } - else - { - if (inplace) - return changed; - if (gimple_has_lhs (stmt)) - { - tree lhs = gimple_get_lhs (stmt); - maybe_push_res_to_seq (rcode, TREE_TYPE (lhs), - ops, &seq, lhs); - gsi_replace_with_seq_vops (gsi, seq); - } - else - gcc_unreachable (); - } - - return true; + return changed; } /* Fold the statement pointed to by GSI. In some cases, this function may Index: gcc/match-builtin.pd =================================================================== --- gcc/match-builtin.pd (revision 214675) +++ gcc/match-builtin.pd (working copy) @@ -18,27 +18,103 @@ along with GCC; see the file COPYING3. . */ -/* One builtin function to atom. */ -(simplify - (BUILT_IN_SQRT (mult @0 @0)) - @0) +/* ??? For math builtins we fail to properly repeat patterns for + all FP type kinds (sqrtf, sqrt, sqrtl). And we fail to provide + a mechanism to iterate two ops in lock-step like + (for fn1 in sqrt sqrtf sqrtl and fn2 in pow powf powl ...) + if we were to do that repetition semi-manually. + We could also automagically use the type of the expr to + always do mathfn_built_in at code-gen time and always + automagically iterate over kinds (but that's bogus for + things like (convert (BUILT_IN_SQRT @0)) -> (BUILT_IN_SQRTF @0). */ + + /* One builtin function to builtin function. */ (simplify (BUILT_IN_CABS (complex:c @0 real_zerop)) - (BUILT_IN_FABS @0)) + (abs @0)) /* One builtin function to expr. */ (simplify (BUILT_IN_CABS (complex @0 @0)) - (mult (BUILT_IN_FABS @0) { build_real (TREE_TYPE (@0), real_value_truncate (TYPE_MODE (TREE_TYPE (@0)), dconst_sqrt2 ())); })) + (mult (abs @0) { build_real (TREE_TYPE (@0), real_value_truncate (TYPE_MODE (TREE_TYPE (@0)), dconst_sqrt2 ())); })) /* One nested fn. */ (simplify (mult:c (BUILT_IN_POW @0 @1) @0) (BUILT_IN_POW @0 (PLUS_EXPR @1 { build_one_cst (TREE_TYPE (@1)); }))) + +/* From fold_builtin_fabs and fold_builtin_abs. */ +/* Fold a call to fabs, fabsf or fabsl, to abs, labs, llabs or imaxabs. */ +(for fn in BUILT_IN_FABS BUILT_IN_FABSF BUILT_IN_FABSL BUILT_IN_ABS BUILT_IN_LABS BUILT_IN_LLABS BUILT_IN_IMAXABS + (simplify + (fn @0) + (abs @0))) + +/* From fold_builtin_pow. */ +/* Optimize pow(1.0,y) = 1.0. */ +(simplify + (BUILT_IN_POW real_onep@0 @1) + @0) (simplify - (BUILT_IN_POW @0 REAL_CST@1) - /* This needs to be conditionalized on flag_unsafe_math_optimizations, - but we keep it for now to exercise function re-optimization. - It makes gcc.dg/pr43419.c FAIL execution though. */ - (if (REAL_VALUES_EQUAL (TREE_REAL_CST (@1), dconsthalf)) - (BUILT_IN_SQRT @0))) + (BUILT_IN_POW @0 REAL_CST@1) + (with { REAL_VALUE_TYPE c = TREE_REAL_CST (@1); } + /* Optimize pow(x,0.0) = 1.0. */ + (if (REAL_VALUES_EQUAL (c, dconst0)) + { build_real (type, dconst1); }) + /* Optimize pow(x,1.0) = x. */ + (if (REAL_VALUES_EQUAL (c, dconst1)) + @0) + /* Optimize pow(x,-1.0) = 1.0/x. */ + (if (REAL_VALUES_EQUAL (c, dconstm1)) + (rdiv { build_real (type, dconst1); } @0)) + /* Optimize pow(x,0.5) = sqrt(x). */ + (if (flag_unsafe_math_optimizations + && REAL_VALUES_EQUAL (c, dconsthalf)) + (BUILT_IN_SQRT @0)) + /* Optimize pow(x,1.0/3.0) = cbrt(x). */ + (with + { const REAL_VALUE_TYPE dconstroot + = real_value_truncate (TYPE_MODE (type), dconst_third ()); } + (if (flag_unsafe_math_optimizations + && REAL_VALUES_EQUAL (c, dconstroot)) + (BUILT_IN_CBRT @0))))) +/* Strip sign ops from even integer powers. + ??? The code in builtins.c manages to perform this recursively + through the whole expression in arg0 of pow. */ +(for sgnop in abs negate + (simplify + (BUILT_IN_POW (sgnop @0) REAL_CST@1) + (with + { + REAL_VALUE_TYPE c = TREE_REAL_CST (@1); + HOST_WIDE_INT n = real_to_integer (&c); + REAL_VALUE_TYPE cint; + real_from_integer (&cint, VOIDmode, n, SIGNED); + } + (if (real_identical (&c, &cint) + && (n & 1) == 0 + && flag_unsafe_math_optimizations) + (BUILT_IN_POW @0 @1))))) +/* From fold_builtin_sqrt. */ +(if (flag_unsafe_math_optimizations) + /* Optimize sqrt(expN(x)) = expN(x*0.5). */ + (for expfn in BUILT_IN_EXP10 BUILT_IN_POW10 BUILT_IN_EXP BUILT_IN_EXP2 + (simplify + (BUILT_IN_SQRT (expfn @0)) + (expfn (mult @0 { build_real (type, dconsthalf); })))) + /* Optimize sqrt(Nroot(x)) -> pow(x,1/(2*N)). */ + (for rootfn in BUILT_IN_SQRT BUILT_IN_CBRT + (simplify + (BUILT_IN_SQRT (rootfn @0)) + (with + { REAL_VALUE_TYPE dconstroot; + if (BUILTIN_SQRT_P (rootfn)) dconstroot = dconsthalf; + else dconstroot = dconst_third (); + /* Adjust for the outer root. */ + SET_REAL_EXP (&dconstroot, REAL_EXP (&dconstroot) - 1); + dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot); } + (BUILT_IN_POW @0 { build_real (type, dconstroot); })))) + /* Optimize sqrt(pow(x,y)) = pow(|x|,y*0.5). */ + (simplify + (BUILT_IN_SQRT (BUILT_IN_POW @0 @1)) + (BUILT_IN_POW (abs @0) (mult @1 { build_real (TREE_TYPE (@1), dconsthalf); })))) Index: gcc/testsuite/gcc.dg/tree-ssa/match-1.c =================================================================== --- gcc/testsuite/gcc.dg/tree-ssa/match-1.c (revision 214675) +++ gcc/testsuite/gcc.dg/tree-ssa/match-1.c (working copy) @@ -1,38 +0,0 @@ -/* { dg-do compile } */ -/* { dg-options "-O -fdump-tree-forwprop1-details" } */ - -double test1 (_Complex double z) -{ - __imag z = 0.; - return __builtin_cabs (z); -} - -/* { dg-final { scan-tree-dump "gimple_simplified to \[^\n\r\]*fabs" "forwprop1" } } */ - -double test2 (double x) -{ - _Complex z = x; - __imag z = x; - return __builtin_cabs (z); -} - -/* { dg-final { scan-tree-dump "gimple_simplified to \[^\n\r\]*= _\\d\+ \\* 1.41" "forwprop1" } } */ - -double test3 (double x) -{ - double y = __builtin_pow (x, 5.); - return y * x; -} - -/* { dg-final { scan-tree-dump "gimple_simplified to \[^\n\r\]*pow \\(x_\\d\+\\(D\\), 6" "forwprop1" } } */ - -double test4 (double w) -{ - double x = w * w; - double y = __builtin_pow (x, -0.5); - return y * x; -} - -/* { dg-final { scan-tree-dump "gimple_simplified to \[^\n\r\]*= w_\\d\+\\(D\\)" "forwprop1" } } */ - -/* { dg-final { cleanup-tree-dump "forwprop1" } } */ Index: gcc/testsuite/gcc.dg/tree-ssa/match-builtins.c =================================================================== --- gcc/testsuite/gcc.dg/tree-ssa/match-builtins.c (revision 214675) +++ gcc/testsuite/gcc.dg/tree-ssa/match-builtins.c (working copy) @@ -26,13 +26,4 @@ double test3 (double x) /* { dg-final { scan-tree-dump "gimple_simplified to \[^\n\r\]*pow \\(x_\\d\+\\(D\\), 6" "forwprop1" } } */ -double test4 (double w) -{ - double x = w * w; - double y = __builtin_pow (x, -0.5); - return y * x; -} - -/* { dg-final { scan-tree-dump "gimple_simplified to \[^\n\r\]*= w_\\d\+\\(D\\)" "forwprop1" } } */ - /* { dg-final { cleanup-tree-dump "forwprop1" } } */ Index: gcc/testsuite/gcc.dg/tree-ssa/match-builtins-fast-math.c =================================================================== --- gcc/testsuite/gcc.dg/tree-ssa/match-builtins-fast-math.c (revision 0) +++ gcc/testsuite/gcc.dg/tree-ssa/match-builtins-fast-math.c (working copy) @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-O -ffast-math -fdump-tree-forwprop1-details" } */ + +double test4 (double w) +{ + double x = w * w; + double y = __builtin_pow (x, -0.5); + return y * x; +} + +/* { dg-final { scan-tree-dump "gimple_simplified to _\\d\+ = ABS_EXPR