From patchwork Tue Jul 7 12:50:29 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kugan Vivekanandarajah X-Patchwork-Id: 50818 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-wi0-f197.google.com (mail-wi0-f197.google.com [209.85.212.197]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 8E845229FC for ; Tue, 7 Jul 2015 12:51:07 +0000 (UTC) Received: by wizo10 with SMTP id o10sf9474217wiz.0 for ; Tue, 07 Jul 2015 05:51:06 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:mailing-list:precedence:list-id :list-unsubscribe:list-archive:list-post:list-help:sender :delivered-to:message-id:date:from:user-agent:mime-version:to:cc :subject:references:in-reply-to:content-type:x-original-sender :x-original-authentication-results; bh=4+GsKPAP58LZL42D+ky+1cRSB2Lfl2UHfcexJhQ6Jno=; b=KQhOnAm1oR1vZglecSjOMd4BFUQ+7S91ThNxPgdNhPh+quHBxjwC1VKscPCK4lXnTA HGqXXDeYEL0Zb1hNVvbj8xLnN2jgz4LbkduD09JagNDdJmWOSvCBSTxcDzeulyisB3kq hBFZiqBpG2Bxh0ebR+tdSY6InKnEzuInQCfAgQ4LsbZgxi3RD+oDTQTy/wBU4yz+4t8P uEOSEdUxDCN6jXDF9Ci06mg33qjObpL7ytqKi28hQvFb9Q2b8wEmkI1C6tgeH9I8AT9/ vmzLz7FblYYdMQNnNYh9EuLOGIdZG66MeGYDMjblv6AOdQwXoyVVgTT7n3iXegjVxPZK sSTA== X-Gm-Message-State: ALoCoQlzSlcX0JeizhAxCTirrHxXSfXhTStQhABB1+/ouvU9CJTQItLDAEzcJPhk7uq4OVsZgZ02 X-Received: by 10.152.8.9 with SMTP id n9mr2064690laa.1.1436273466809; Tue, 07 Jul 2015 05:51:06 -0700 (PDT) X-BeenThere: patchwork-forward@linaro.org Received: by 10.152.234.108 with SMTP id ud12ls47502lac.43.gmail; Tue, 07 Jul 2015 05:51:06 -0700 (PDT) X-Received: by 10.152.6.196 with SMTP id d4mr3934974laa.77.1436273466668; Tue, 07 Jul 2015 05:51:06 -0700 (PDT) Received: from mail-la0-x22d.google.com (mail-la0-x22d.google.com. [2a00:1450:4010:c03::22d]) by mx.google.com with ESMTPS id t5si18075683lbb.35.2015.07.07.05.51.06 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 07 Jul 2015 05:51:06 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 2a00:1450:4010:c03::22d as permitted sender) client-ip=2a00:1450:4010:c03::22d; Received: by laar3 with SMTP id r3so194138511laa.0 for ; Tue, 07 Jul 2015 05:51:06 -0700 (PDT) X-Received: by 10.152.7.7 with SMTP id f7mr3922113laa.106.1436273466547; Tue, 07 Jul 2015 05:51:06 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.112.108.230 with SMTP id hn6csp2368393lbb; Tue, 7 Jul 2015 05:51:04 -0700 (PDT) X-Received: by 10.68.191.167 with SMTP id gz7mr8737727pbc.43.1436273464023; Tue, 07 Jul 2015 05:51:04 -0700 (PDT) Received: from sourceware.org (server1.sourceware.org. [209.132.180.131]) by mx.google.com with ESMTPS id a10si34544368pas.176.2015.07.07.05.51.02 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 07 Jul 2015 05:51:04 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-return-402231-patch=linaro.org@gcc.gnu.org designates 209.132.180.131 as permitted sender) client-ip=209.132.180.131; Received: (qmail 34614 invoked by alias); 7 Jul 2015 12:50:50 -0000 Mailing-List: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org Precedence: list 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 34604 invoked by uid 89); 7 Jul 2015 12:50:49 -0000 X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.1 required=5.0 tests=AWL, BAYES_50, RCVD_IN_DNSWL_LOW, SPF_PASS autolearn=ham version=3.3.2 X-HELO: mail-pd0-f170.google.com Received: from mail-pd0-f170.google.com (HELO mail-pd0-f170.google.com) (209.85.192.170) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-GCM-SHA256 encrypted) ESMTPS; Tue, 07 Jul 2015 12:50:42 +0000 Received: by pdbci14 with SMTP id ci14so125460035pdb.2 for ; Tue, 07 Jul 2015 05:50:40 -0700 (PDT) X-Received: by 10.70.88.43 with SMTP id bd11mr8581712pdb.7.1436273440551; Tue, 07 Jul 2015 05:50:40 -0700 (PDT) Received: from [10.1.1.8] (58-6-183-210.dyn.iinet.net.au. [58.6.183.210]) by mx.google.com with ESMTPSA id qa10sm21780956pbc.44.2015.07.07.05.50.36 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 07 Jul 2015 05:50:38 -0700 (PDT) Message-ID: <559BCB15.9010209@linaro.org> Date: Tue, 07 Jul 2015 22:50:29 +1000 From: Kugan User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.7.0 MIME-Version: 1.0 To: Jeff Law , Bernhard Reutner-Fischer CC: "gcc-patches@gcc.gnu.org" Subject: Re: [PR66726] Factor conversion out of COND_EXPR References: <55974BF2.3060603@linaro.org> <20150704085143.GA14895@nbbrfq.cc.univie.ac.at> <5597D24B.8010900@linaro.org> <559AF515.6010700@redhat.com> In-Reply-To: <559AF515.6010700@redhat.com> X-IsSubscribed: yes X-Original-Sender: kugan.vivekanandarajah@linaro.org X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 2a00:1450:4010:c03::22d as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org; dkim=pass header.i=@gcc.gnu.org X-Google-Group-Id: 836684582541 On 07/07/15 07:37, Jeff Law wrote: > On 07/04/2015 06:32 AM, Kugan wrote: > I would also verify that this turns into a MIN_EXPR. I think the patch > as-written won't detect the MIN_EXPR until the _next_ time phi-opt is > called. And one of the benefits we're really looking for here is to > remove barriers to finding these min/max expressions. > > >> + >> diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c >> index d2a5cee..12ab9ee 100644 >> --- a/gcc/tree-ssa-phiopt.c >> +++ b/gcc/tree-ssa-phiopt.c >> @@ -73,6 +73,7 @@ along with GCC; see the file COPYING3. If not see >> static unsigned int tree_ssa_phiopt_worker (bool, bool); >> static bool conditional_replacement (basic_block, basic_block, >> edge, edge, gphi *, tree, tree); >> +static bool factor_out_conditional_conversion (edge, edge, gphi *, >> tree, tree); >> static int value_replacement (basic_block, basic_block, >> edge, edge, gimple, tree, tree); >> static bool minmax_replacement (basic_block, basic_block, >> @@ -342,6 +343,8 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool >> do_hoist_loads) >> cfgchanged = true; >> else if (minmax_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) >> cfgchanged = true; >> + else if (factor_out_conditional_conversion (e1, e2, phi, arg0, >> arg1)) >> + cfgchanged = true; > So this transformation does not inherently change the CFG, so setting > CFGCHANGED isn't really appropriate and may trigger unnecessary cleanups. > > I think the transformation needs to occur prior this if-elseif-else > block since the transformation should enable the code in the > if-elseif-else block to find more optimization opportunities. > > That will also imply we either restart after the transformation applies, > or we update the local variables that are used as arguments to > conditional_replacement, abs_replacement and minmax_replacement. > > >> } >> } >> >> @@ -410,6 +413,108 @@ replace_phi_edge_with_variable (basic_block >> cond_block, >> bb->index); >> } >> >> +/* PR66726: Factor conversion out of COND_EXPR. If the arguments of >> the PHI >> + stmt are CONVERT_STMT, factor out the conversion and perform the >> conversion >> + to the result of PHI stmt. */ >> + >> +static bool >> +factor_out_conditional_conversion (edge e0, edge e1, gphi *phi, >> + tree arg0, tree arg1) >> +{ >> + gimple def0 = NULL, def1 = NULL, new_stmt; >> + tree new_arg0 = NULL_TREE, new_arg1 = NULL_TREE; >> + tree temp, result; >> + gimple_stmt_iterator gsi; >> + >> + /* One of the arguments has to be SSA_NAME and other argument can >> + be an SSA_NAME of INTEGER_CST. */ >> + if ((TREE_CODE (arg0) != SSA_NAME >> + && TREE_CODE (arg0) != INTEGER_CST) >> + || (TREE_CODE (arg1) != SSA_NAME >> + && TREE_CODE (arg1) != INTEGER_CST) >> + || (TREE_CODE (arg0) == INTEGER_CST >> + && TREE_CODE (arg1) == INTEGER_CST)) >> + return false; >> + >> + /* Handle only PHI statements with two arguments. TODO: If all >> + other arguments to PHI are INTEGER_CST, we can handle more >> + than two arguments too. */ >> + if (gimple_phi_num_args (phi) != 2) >> + return false; > If you're just handling two arguments, then it's probably easiest to > just swap arg0/arg1 e0/e1 if arg0 is not an SSA_NAME like this: > > /* First canonicalize to simplify tests. */ > if (TREE_CODE (arg0) != SSA_NAME) > { > std::swap (arg0, arg1); > std::swap (e0, e1); > } > > if (TREE_CODE (arg0) != SSA_NAME) > return false; > > That simplifies things a bit since you're going to know from thsi point > forward that arg0 is an SSA_NAME. > > > >> + >> + /* If arg0 is an SSA_NAME and the stmt which defines arg0 is >> + a CONVERT_STMT, use the LHS as new_arg0. */ >> + if (TREE_CODE (arg0) == SSA_NAME) >> + { >> + def0 = SSA_NAME_DEF_STMT (arg0); >> + if (!is_gimple_assign (def0) >> + || !CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def0))) >> + return false; >> + new_arg0 = gimple_assign_rhs1 (def0); >> + } > Use gimple_assign_cast_p rather than checking CONVERT_EXPR_CODE_P > directly, so something like: > > /* Now see if ARG0 was defined by a typecast. */ > gimple arg0_def = SSA_NAME_DEF_STMT (arg0); > > if (!is_gimple_assign (arg0_def) || !gimple_assign_cast_p (arg0_def)) > return false; > > Similarly for arg1 when it's an SSA_NAME. > > >> + >> + /* If types of new_arg0 and new_arg1 are different bailout. */ >> + if (TREE_TYPE (new_arg0) != TREE_TYPE (new_arg1)) >> + return false; > Do we want to restrict this to just integral types? I haven't though > about it too deeply, so perhaps not. > >> + >> + /* Replace the PHI stmt with the new_arg0 and new_arg1. Also insert >> + a new CONVERT_STMT that converts the phi results. */ >> + gsi = gsi_after_labels (gimple_bb (phi)); >> + result = PHI_RESULT (phi); >> + temp = make_ssa_name (TREE_TYPE (new_arg0), phi); >> + >> + if (dump_file && (dump_flags & TDF_DETAILS)) >> + { >> + fprintf (dump_file, "PHI "); >> + print_generic_expr (dump_file, gimple_phi_result (phi), 0); >> + fprintf (dump_file, >> + " changed to factor CONVERT_EXPR out from COND_EXPR.\n"); >> + fprintf (dump_file, "New PHI_RESULT is "); >> + print_generic_expr (dump_file, temp, 0); >> + fprintf (dump_file, " and new stmt with CONVERT_EXPR defines "); >> + print_generic_expr (dump_file, result, 0); >> + fprintf (dump_file, ".\n"); >> + } >> + >> + gimple_phi_set_result (phi, temp); >> + SET_PHI_ARG_DEF (phi, e0->dest_idx, new_arg0); >> + SET_PHI_ARG_DEF (phi, e1->dest_idx, new_arg1); >> + new_stmt = gimple_build_assign (result, CONVERT_EXPR, temp); >> + gsi_insert_before (&gsi, new_stmt, GSI_SAME_STMT); >> + return true; > So I think you want to also remove the old cast(s) so that the minmax > optimization can apply without having to wait for another pass of phi-opt. > > To safely remove the old cast(s) you have to verify the result of the > cast has a single use (which is obviously in the PHI). Otherwise your > transformation will have introduced a runtime redundancy. > > I also suspect it's better to create a new PHI rather than modify the > original PHI. The original PHI should be removed and the result re-used > as the result of the new convert statement. > > Extra points if you can easily make this transformation apply to a > generic unary operator. So for example, we might have a sinkable bit-not. > > Overall it's heading the right direction. But I think it needs another > iteration. Thanks for the review. I have addressed your comments above in the attached patch. I have one question with respect to unary operation. For generic unary operation with INTEGER_CST, do we skip this or do we have to perform the inverse operation so that the conversion after PHI will restore it? Is there any easy way to do this safely? Bootstrapped and regression tested the attached patch on x86-64-none-linux-gnu with no new regressions. Thanks, Kugan diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr66726.c b/gcc/testsuite/gcc.dg/tree-ssa/pr66726.c index e69de29..a4c7418 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/pr66726.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr66726.c @@ -0,0 +1,15 @@ + +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-phiopt1-details" } */ + +extern unsigned short mode_size[]; + +int +oof (int mode) +{ + return (64 < mode_size[mode] ? 64 : mode_size[mode]); +} + +/* { dg-final { scan-tree-dump-times "factor conversion out" 1 "phiopt1" } } */ +/* { dg-final { scan-tree-dump-times "MIN_EXPR" 1 "phiopt1" } } */ + diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c index 92b4ab0..1d6de9b 100644 --- a/gcc/tree-ssa-phiopt.c +++ b/gcc/tree-ssa-phiopt.c @@ -73,6 +73,7 @@ along with GCC; see the file COPYING3. If not see static unsigned int tree_ssa_phiopt_worker (bool, bool); static bool conditional_replacement (basic_block, basic_block, edge, edge, gphi *, tree, tree); +static bool factor_out_conditional_conversion (edge, edge, gphi *, tree, tree); static int value_replacement (basic_block, basic_block, edge, edge, gimple, tree, tree); static bool minmax_replacement (basic_block, basic_block, @@ -335,6 +336,17 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads) node. */ gcc_assert (arg0 != NULL && arg1 != NULL); + if (factor_out_conditional_conversion (e1, e2, phi, arg0, arg1)) + { + /* Update arg0 and arg1. */ + phis = phi_nodes (bb2); + phi = single_non_singleton_phi_for_edges (phis, e1, e2); + gcc_assert (phi); + arg0 = gimple_phi_arg_def (phi, e1->dest_idx); + arg1 = gimple_phi_arg_def (phi, e2->dest_idx); + gcc_assert (arg0 != NULL && arg1 != NULL); + } + /* Do the replacement of conditional if it can be done. */ if (conditional_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) cfgchanged = true; @@ -410,6 +422,133 @@ replace_phi_edge_with_variable (basic_block cond_block, bb->index); } +/* PR66726: Factor conversion out of COND_EXPR. If the arguments of the PHI + stmt are CONVERT_STMT, factor out the conversion and perform the conversion + to the result of PHI stmt. */ + +static bool +factor_out_conditional_conversion (edge e0, edge e1, gphi *phi, + tree arg0, tree arg1) +{ + gimple arg0_def_stmt = NULL, arg1_def_stmt = NULL, new_stmt; + tree new_arg0 = NULL_TREE, new_arg1 = NULL_TREE; + tree temp, result; + gphi *newphi; + gimple_stmt_iterator gsi, gsi_for_def; + source_location locus = gimple_location (phi); + enum tree_code convert_code; + + /* Handle only PHI statements with two arguments. TODO: If all + other arguments to PHI are INTEGER_CST, we can handle more + than two arguments too. */ + if (gimple_phi_num_args (phi) != 2) + return false; + + /* First canonicalize to simplify tests. */ + if (TREE_CODE (arg0) != SSA_NAME) + { + std::swap (arg0, arg1); + std::swap (e0, e1); + } + + if (TREE_CODE (arg0) != SSA_NAME + || (TREE_CODE (arg1) != SSA_NAME + && TREE_CODE (arg1) != INTEGER_CST)) + return false; + + /* If arg0 is an SSA_NAME and the stmt which defines arg0 is + a conversion. */ + arg0_def_stmt = SSA_NAME_DEF_STMT (arg0); + if (!is_gimple_assign (arg0_def_stmt) + || (!gimple_assign_cast_p (arg0_def_stmt) + && (get_gimple_rhs_class (gimple_assign_rhs_code (arg0_def_stmt)) + != GIMPLE_UNARY_RHS))) + return false; + + /* Use the LHS as new_arg0. */ + convert_code = gimple_assign_rhs_code (arg0_def_stmt); + new_arg0 = gimple_assign_rhs1 (arg0_def_stmt); + if (convert_code == VIEW_CONVERT_EXPR) + new_arg0 = TREE_OPERAND (new_arg0, 0); + + /* If arg1 is an SSA_NAME and the stmt which defines arg0 is + a conversion. */ + if (TREE_CODE (arg1) == SSA_NAME) + { + arg1_def_stmt = SSA_NAME_DEF_STMT (arg1); + if (!is_gimple_assign (arg1_def_stmt) + || gimple_assign_rhs_code (arg1_def_stmt) != convert_code) + return false; + + /* Use the LHS as new_arg1. */ + new_arg1 = gimple_assign_rhs1 (arg1_def_stmt); + if (gimple_assign_rhs_code (arg1_def_stmt) == VIEW_CONVERT_EXPR) + new_arg1 = TREE_OPERAND (new_arg1, 0); + } + else + { + /* If arg1 is an INTEGER_CST, fold it to new type. */ + if (INTEGRAL_TYPE_P (TREE_TYPE (new_arg0)) + && int_fits_type_p (arg1, TREE_TYPE (new_arg0))) + { + if (gimple_assign_cast_p (arg0_def_stmt)) + new_arg1 = fold_convert (TREE_TYPE (new_arg0), arg1); + else + return false; + } + else + return false; + } + + /* If types of new_arg0 and new_arg1 are different bailout. */ + if (TREE_TYPE (new_arg0) != TREE_TYPE (new_arg1)) + return false; + + /* Create a new PHI stmt. */ + result = PHI_RESULT (phi); + temp = make_ssa_name (TREE_TYPE (new_arg0), NULL); + newphi = create_phi_node (temp, gimple_bb (phi)); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "PHI "); + print_generic_expr (dump_file, gimple_phi_result (phi), 0); + fprintf (dump_file, + " changed to factor conversion out from COND_EXPR.\n"); + fprintf (dump_file, "New stmt with CAST that defines "); + print_generic_expr (dump_file, result, 0); + fprintf (dump_file, ".\n"); + } + + /* Remove the old cast(s) that has single use. */ + if (arg0_def_stmt && has_single_use (arg0)) + { + gsi_for_def = gsi_for_stmt (arg0_def_stmt); + gsi_remove (&gsi_for_def, true); + } + + if (arg1_def_stmt && has_single_use (arg1)) + { + gsi_for_def = gsi_for_stmt (arg1_def_stmt); + gsi_remove (&gsi_for_def, true); + } + + add_phi_arg (newphi, new_arg0, e0, locus); + add_phi_arg (newphi, new_arg1, e1, locus); + + /* Create the conversion stmt and insert it. */ + if (convert_code == VIEW_CONVERT_EXPR) + temp = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (result), temp); + new_stmt = gimple_build_assign (result, convert_code, temp); + gsi = gsi_after_labels (gimple_bb (phi)); + gsi_insert_before (&gsi, new_stmt, GSI_SAME_STMT); + + /* Remove he original PHI stmt. */ + gsi = gsi_for_stmt (phi); + gsi_remove (&gsi, true); + return true; +} + /* The function conditional_replacement does the main work of doing the conditional replacement. Return true if the replacement is done. Otherwise return false. @@ -2142,6 +2281,26 @@ gate_hoist_loads (void) This pass also performs a fifth transformation of a slightly different flavor. + Factor conversion in COND_EXPR + ------------------------------ + + This transformation factors the conversion out of COND_EXPR with + factor_out_conditional_conversion. + + For example: + if (a <= CST) goto ; else goto ; + : + tmp = (int) a; + : + tmp = PHI + + Into: + if (a <= CST) goto ; else goto ; + : + : + a = PHI + tmp = (int) a; + Adjacent Load Hoisting ----------------------