From patchwork Sat Mar 1 14:33:52 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marc Glisse X-Patchwork-Id: 325422 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 29ABC2C0089 for ; Sun, 2 Mar 2014 01:34:20 +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:subject:message-id:mime-version:content-type :content-id; q=dns; s=default; b=GtTqXVT8NsRyzstytyNtuEWamO8tCa7 begHBtvMJRlHmV7uLNLDgxprClJH6+k41TMH1fpKuSM4SZYE8gS+Nbr6PdfEZUby 3J/V75G9LbxdWByLwbMEBXvjUSNiQ4k1oHCFEeZcc5QVxLDlOIISt7y59bpsfugb p/kH/s7Ed4rI= 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 :content-id; s=default; bh=q2/QGWxUmuXivjIGRcUsakqO940=; b=pra83 sKi/3yFCZaSs39UaUom3G1HYuy03C+6mLNr56OR5goix5Mc3ZmqLoYTWtf8zAwvH AiQhC206CP7PCJADV+UeDQzeiplTh6jxC1MZVWoSzvq8GC+DOOpDzghpPOVmuz2r u95VuEcqbLnH+Q1q1bzrVPHyoEQnCfAJbZAGg4= Received: (qmail 23916 invoked by alias); 1 Mar 2014 14:34:12 -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 23904 invoked by uid 89); 1 Mar 2014 14:34:12 -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: mail3-relais-sop.national.inria.fr Received: from mail3-relais-sop.national.inria.fr (HELO mail3-relais-sop.national.inria.fr) (192.134.164.104) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (CAMELLIA256-SHA encrypted) ESMTPS; Sat, 01 Mar 2014 14:34:10 +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; 01 Mar 2014 15:33:52 +0100 Received: from glisse (helo=localhost) by stedding.saclay.inria.fr with local-esmtp (Exim 4.82) (envelope-from ) id 1WJkzA-0000rq-3C for gcc-patches@gcc.gnu.org; Sat, 01 Mar 2014 15:33:52 +0100 Date: Sat, 1 Mar 2014 15:33:52 +0100 (CET) From: Marc Glisse To: gcc-patches@gcc.gnu.org Subject: Optimize n?rotate(x,n):x Message-ID: User-Agent: Alpine 2.02 (DEB 1266 2009-07-14) MIME-Version: 1.0 Content-ID: Hello, again, a stage 1 patch that I will ping then, but early comments are welcome. PR 59100 was asking to transform n?rotate(x,n):x to rotate(x,n) (because it can be hard to write a strictly valid rotate in plain C). The operation is really: (x != neutral) ? x op y : y where neutral is such that (neutral op y) is always y, so that's what I implemented (and absorbing elements while I was at it). For some operations on some platforms, the transformation may not be such a good idea, in particular if division is very slow and b is 1 most of the time, then computing a/b may be slower than (b!=1)?a/b:a. The easiest might be to comment out those operations in the switch for now. I think divisions are the only ones slow enough to deserve this, though there certainly are CPUs where multiplication is not so fast, and even for rotate it may not always be a win if the processor doesn't have a rotate instruction and the shift amount is almost always 0. Passes bootstrap+testsuite on x86_64-linux-gnu. 2014-03-01 Marc Glisse PR tree-optimization/59100 gcc/ * tree-ssa-phiopt.c (neutral_element_p, absorbing_element_p): New functions. (value_replacement): Handle conditional binary operations with a neutral or absorbing element. gcc/testsuite/ * gcc.dg/tree-ssa/phi-opt-12.c: New file. Index: gcc/testsuite/gcc.dg/tree-ssa/phi-opt-12.c =================================================================== --- gcc/testsuite/gcc.dg/tree-ssa/phi-opt-12.c (revision 0) +++ gcc/testsuite/gcc.dg/tree-ssa/phi-opt-12.c (working copy) @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-phiopt1" } */ + +int f(int a, int b, int c) { + if (c > 5) return c; + if (a == 0) return b; + return a + b; +} + +unsigned rot(unsigned x, int n) { + const int bits = __CHAR_BIT__ * __SIZEOF_INT__; + return (n == 0) ? x : ((x << n) | (x >> (bits - n))); +} + +unsigned m(unsigned a, unsigned b) { + if (a == 0) + return 0; + else + return a & b; +} + +/* { dg-final { scan-tree-dump-times "goto" 2 "phiopt1" } } */ +/* { dg-final { cleanup-tree-dump "phiopt1" } } */ Property changes on: gcc/testsuite/gcc.dg/tree-ssa/phi-opt-12.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Author Date Id Revision URL \ No newline at end of property Index: gcc/tree-ssa-phiopt.c =================================================================== --- gcc/tree-ssa-phiopt.c (revision 208241) +++ gcc/tree-ssa-phiopt.c (working copy) @@ -140,20 +140,37 @@ static bool gate_hoist_loads (void); x = PHI (CONST, a) Gets replaced with: bb0: bb2: t1 = a == CONST; t2 = b > c; t3 = t1 & t2; x = a; + + It also replaces + + bb0: + if (a != 0) goto bb1; else goto bb2; + bb1: + c = a + b; + bb2: + x = PHI ; + + with + + bb0: + c = a + b; + bb2: + x = PHI ; + ABS Replacement --------------- This transformation, implemented in abs_replacement, replaces bb0: if (a >= 0) goto bb2; else goto bb1; bb1: x = -a; bb2: @@ -809,20 +826,79 @@ operand_equal_for_value_replacement (con if (rhs_is_fed_for_value_replacement (arg0, arg1, code, tmp)) return true; tmp = gimple_assign_rhs2 (def); if (rhs_is_fed_for_value_replacement (arg0, arg1, code, tmp)) return true; return false; } +/* Returns true if ARG is a neutral element for operation CODE + on the RIGHT side. */ + +static bool +neutral_element_p (tree_code code, tree arg, bool right) +{ + switch (code) + { + case PLUS_EXPR: + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + return integer_zerop (arg); + + case LROTATE_EXPR: + case RROTATE_EXPR: + case LSHIFT_EXPR: + case RSHIFT_EXPR: + case MINUS_EXPR: + case POINTER_PLUS_EXPR: + return right && integer_zerop (arg); + + case MULT_EXPR: + return integer_onep (arg); + + // Are those too expensive? Should we check edge probabilities? + case TRUNC_DIV_EXPR: + case CEIL_DIV_EXPR: + case FLOOR_DIV_EXPR: + case ROUND_DIV_EXPR: + case EXACT_DIV_EXPR: + return right && integer_onep (arg); + + case BIT_AND_EXPR: + return integer_all_onesp (arg); + + default: + return false; + } +} + +/* Returns true if ARG is an absorbing element for operation CODE. */ + +static bool +absorbing_element_p (tree_code code, tree arg) +{ + switch (code) + { + case BIT_IOR_EXPR: + return integer_all_onesp (arg); + + case MULT_EXPR: + case BIT_AND_EXPR: + return integer_zerop (arg); + + default: + return false; + } +} + /* The function value_replacement does the main work of doing the value replacement. Return non-zero if the replacement is done. Otherwise return 0. If we remove the middle basic block, return 2. BB is the basic block where the replacement is going to be done on. ARG0 is argument 0 from the PHI. Likewise for ARG1. */ static int value_replacement (basic_block cond_bb, basic_block middle_bb, edge e0, edge e1, gimple phi, tree arg0, tree arg1) @@ -833,23 +909,21 @@ value_replacement (basic_block cond_bb, enum tree_code code; bool emtpy_or_with_defined_p = true; /* If the type says honor signed zeros we cannot do this optimization. */ if (HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg1)))) return 0; /* If there is a statement in MIDDLE_BB that defines one of the PHI arguments, then adjust arg0 or arg1. */ - gsi = gsi_after_labels (middle_bb); - if (!gsi_end_p (gsi) && is_gimple_debug (gsi_stmt (gsi))) - gsi_next_nondebug (&gsi); + gsi = gsi_start_nondebug_after_labels_bb (middle_bb); while (!gsi_end_p (gsi)) { gimple stmt = gsi_stmt (gsi); tree lhs; gsi_next_nondebug (&gsi); if (!is_gimple_assign (stmt)) { emtpy_or_with_defined_p = false; continue; } @@ -931,20 +1005,57 @@ value_replacement (basic_block cond_bb, print_generic_expr (dump_file, gimple_phi_result (phi), 0); fprintf (dump_file, " reduced for COND_EXPR in block %d to ", cond_bb->index); print_generic_expr (dump_file, arg, 0); fprintf (dump_file, ".\n"); } return 1; } } + + /* Now optimize (x != 0) ? x + y : y to just y. + The following condition is too restrictive, there can easily be another + stmt in middle_bb, for instance a CONVERT_EXPR for the second argument. */ + gimple assign = last_and_only_stmt (middle_bb); + if (!assign || gimple_code (assign) != GIMPLE_ASSIGN + || gimple_assign_rhs_class (assign) != GIMPLE_BINARY_RHS) + return 0; + + tree lhs = gimple_assign_lhs (assign); + tree rhs1 = gimple_assign_rhs1 (assign); + tree rhs2 = gimple_assign_rhs2 (assign); + enum tree_code code_def = gimple_assign_rhs_code (assign); + tree cond_lhs = gimple_cond_lhs (cond); + tree cond_rhs = gimple_cond_rhs (cond); + + if (((code == NE_EXPR && e1 == false_edge) + || (code == EQ_EXPR && e1 == true_edge)) + && arg0 == lhs + && ((arg1 == rhs1 + && operand_equal_for_phi_arg_p (rhs2, cond_lhs) + && neutral_element_p (code_def, cond_rhs, true)) + || (arg1 == rhs2 + && operand_equal_for_phi_arg_p (rhs1, cond_lhs) + && neutral_element_p (code_def, cond_rhs, false)) + || (operand_equal_for_phi_arg_p (arg1, cond_rhs) + && (operand_equal_for_phi_arg_p (rhs2, cond_lhs) + || operand_equal_for_phi_arg_p (rhs1, cond_lhs)) + && absorbing_element_p (code_def, cond_rhs)))) + { + gsi = gsi_for_stmt (cond); + gimple_stmt_iterator gsi_from = gsi_for_stmt (assign); + gsi_move_before (&gsi_from, &gsi); + replace_phi_edge_with_variable (cond_bb, e1, phi, lhs); + return 2; + } + return 0; } /* The function minmax_replacement does the main work of doing the minmax replacement. Return true if the replacement is done. Otherwise return false. BB is the basic block where the replacement is going to be done on. ARG0 is argument 0 from the PHI. Likewise for ARG1. */ static bool