From patchwork Tue Sep 20 02:05:29 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kugan Vivekanandarajah X-Patchwork-Id: 76572 Delivered-To: patch@linaro.org Received: by 10.140.106.72 with SMTP id d66csp1246978qgf; Mon, 19 Sep 2016 19:06:14 -0700 (PDT) X-Received: by 10.98.156.193 with SMTP id u62mr10186940pfk.57.1474337174485; Mon, 19 Sep 2016 19:06:14 -0700 (PDT) Return-Path: Received: from sourceware.org (server1.sourceware.org. [209.132.180.131]) by mx.google.com with ESMTPS id j67si5691038pfg.62.2016.09.19.19.06.14 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 19 Sep 2016 19:06:14 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-return-436290-patch=linaro.org@gcc.gnu.org designates 209.132.180.131 as permitted sender) client-ip=209.132.180.131; Authentication-Results: mx.google.com; dkim=pass header.i=@gcc.gnu.org; spf=pass (google.com: domain of gcc-patches-return-436290-patch=linaro.org@gcc.gnu.org designates 209.132.180.131 as permitted sender) smtp.mailfrom=gcc-patches-return-436290-patch=linaro.org@gcc.gnu.org; dmarc=fail (p=NONE dis=NONE) header.from=linaro.org DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :subject:to:references:cc:from:message-id:date:mime-version :in-reply-to:content-type; q=dns; s=default; b=yuJ+9q1rVAy5iy2NO yZgtzd12pS+Vdpen8UeEXquuXiTJ9/1inFEDd+zFqTrocRdiAIzhuvHYJ7RlURqz N/KSiXvXRW32G6ngv32+nm/A+XayMGofi5hFE17wPk4tkqdIY0/AZkAMo9NbLOH6 dArqfDZqb2eBQMjguphI1jp33c= 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 :subject:to:references:cc:from:message-id:date:mime-version :in-reply-to:content-type; s=default; bh=tsOBz0n/RXpI5XT8L2fgxPA fQyg=; b=wK/uVJNbcPCn/Z8MFSK2VqHgIS5bpFiswa4xmAtje/UD4yDqH8bIFPz 6RMFnsuIbqBIxpHeTS6jsI1uDgX0Z1D5HB0HDJTyTQ0Kp1GuQvISt1HJZEwPPrdJ bUr3YVVBY21EZqXTODucc5vlC56QVAtngrpwDJzukscsEFUeOpKk= Received: (qmail 42078 invoked by alias); 20 Sep 2016 02:05:51 -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 42042 invoked by uid 89); 20 Sep 2016 02:05:48 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.1 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_LOW, RCVD_IN_SORBS_SPAM, SPF_PASS autolearn=ham version=3.3.2 spammy=2016-09-20, Yeah, 15, 11, 1511 X-HELO: mail-pf0-f171.google.com Received: from mail-pf0-f171.google.com (HELO mail-pf0-f171.google.com) (209.85.192.171) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 20 Sep 2016 02:05:37 +0000 Received: by mail-pf0-f171.google.com with SMTP id p64so1435933pfb.1 for ; Mon, 19 Sep 2016 19:05:37 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:subject:to:references:cc:from:message-id:date :user-agent:mime-version:in-reply-to; bh=xslRlrhuqVtxctvWZAjC2TtfYUs6pJjMPIXj+IXNlnc=; b=j+9APX3bmvJ+jE4+CpjKhaVCT5f5eDCVvaXxQ+wSULa6JA2rVou0ZVPkGjEOOjIFGt ODvIXMVyRzNcvwJP+ycWw6lT4nXdDpCT0sCWRUGT3QC7+dPgJqb5tiSNJoGfdf1IB8Ee ZsIHsoz33lR3wiTtp82jZnyc+rgKWkqncLBIIrdJJ93aKkdCnS3Z1+zfbjFj+oxhYOQ0 +TJUybTxK1NqFr4oUXLi9Rcrp9Y9jjB/n+125Yy8Pz+7SnClLpLhtXNRy6+MBQmiltd8 tTsP2kEA6iHkx8mncfKQQWuU7/hOtx9uLHyzdApoHGrYhnRu485BZIyg92FW5RbWxQ7l wIAQ== X-Gm-Message-State: AE9vXwN6XaYJG798GKCw1L1nfC57Lx2IlSxiA61E+QNkf3IfiR8k1Ky1FsT/uPCwhmjVWVZo X-Received: by 10.98.27.195 with SMTP id b186mr6998920pfb.111.1474337135603; Mon, 19 Sep 2016 19:05:35 -0700 (PDT) Received: from [10.1.1.7] (58-6-183-210.dyn.iinet.net.au. [58.6.183.210]) by smtp.gmail.com with ESMTPSA id z187sm74316229pfz.39.2016.09.19.19.05.32 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 19 Sep 2016 19:05:34 -0700 (PDT) Subject: Re: [RFC][IPA-VRP] Early VRP Implementation To: Richard Biener References: <57886949.8010300@linaro.org> <19ff8188-aed7-0f9e-cc0b-0603698787ff@linaro.org> <48e42d0c-057c-312a-4e41-cd78c8b38b5e@linaro.org> <4053004a-4dea-9219-a2c4-1d33b0d4d2f9@linaro.org> Cc: Andrew Pinski , "gcc-patches@gcc.gnu.org" , Jan Hubicka , Martin Jambor From: kugan Message-ID: <2fc6782e-fbb8-c955-c3a7-f2e9b8845134@linaro.org> Date: Tue, 20 Sep 2016 12:05:29 +1000 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.2.0 MIME-Version: 1.0 In-Reply-To: X-IsSubscribed: yes Hi Richard, Thanks for the review. On 19/09/16 22:56, Richard Biener wrote: > On Sun, Sep 18, 2016 at 10:50 PM, kugan > wrote: >> Hi Richard, >> >> >> >> On 16/09/16 20:21, Richard Biener wrote: >>> >>> On Fri, Sep 16, 2016 at 7:59 AM, kugan >>> wrote: >>>> >>>> Hi Richard, >>>> >>>> Thanks for the review. >>>> >>>> On 14/09/16 22:04, Richard Biener wrote: >>>>> >>>>> >>>>> On Tue, Aug 23, 2016 at 4:11 AM, Kugan Vivekanandarajah >>>>> wrote: >>>>>> >>>>>> >>>>>> Hi, >>>>>> >>>>>> On 19 August 2016 at 21:41, Richard Biener >>>>>> wrote: >>>>>>> >>>>>>> >>>>>>> On Tue, Aug 16, 2016 at 9:45 AM, kugan >>>>>>> wrote: >>>>>>>> >>>>>>>> >>>>>>>> Hi Richard, >>>> >>>> >>>> >>>>>>>> I am now having -ftree-evrp which is enabled all the time. But This >>>>>>>> will >>>>>>>> only be used for disabling the early-vrp. That is, early-vrp will be >>>>>>>> run >>>>>>>> when ftree-vrp is enabled and ftree-evrp is not explicitly disabled. >>>>>>>> Is >>>>>>>> this >>>>>>>> OK? >>>>>>> >>>>>>> >>>>>>> >>>>>>> Why would one want to disable early-vrp? I see you do this in the >>>>>>> testsuite >>>>>>> for non-early VRP unit-tests but using -fdisable-tree-evrp1 there >>>>>>> would be ok as well. >>>>>> >>>>>> >>>>>> >>>>>> Removed it altogether. I though that you wanted a way to disable >>>>>> early-vrp for testing purposes. >>>>> >>>>> >>>>> >>>>> But there is via the generic -fdisable-tree-DUMPFILE way. >>>> >>>> >>>> >>>> OK. I didnt know about that. >>>> >>>> >>>>>>> Note that you want to have a custom valueize function instead of just >>>>>>> follow_single_use_edges as you want to valueize all SSA names >>>>>>> according >>>>>>> to their lattice value (if it has a single value). You can use >>>>>>> vrp_valueize >>>>>>> for this though that gets you non-single-use edge following as well. >>>>>>> Eventually it's going to be cleaner to do what the SSA propagator does >>>>>>> and >>>>>>> before folding do >>>>>>> >>>>>>> did_replace = replace_uses_in (stmt, vrp_valueize); >>>>>>> if (fold_stmt (&gsi, follow_single_use_edges) >>>>>>> || did_replace) >>>>>>> update_stmt (gsi_stmt (gsi)); >>>>>>> >>>>>>> exporting replace_uses_in for this is ok. I guess I prefer this for >>>>>>> now. >>>>>> >>>>>> >>>>>> >>>>>> I also added the above. I noticed that I need >>>>>> recompute_tree_invariant_for_addr_expr as in ssa_propagate. My initial >>>>>> implementation also had gimple_purge_all_dead_eh_edges and >>>>>> fixup_noreturn_call as in ssa_propagat but I thinj that is not needed >>>>>> as it would be done at the end of the pass. >>>>> >>>>> >>>>> >>>>> I don't see this being done at the end of the pass. So please >>>>> re-instantiate >>>>> that parts. >>>> >>>> >>>> >>>> I have copied these part as well. >>>> >>>>>> With this I noticed more stmts are folded before vrp1. This required >>>>>> me to adjust some testcases. >>>>>> >>>>>>> >>>>>>> Overall this now looks good apart from the folding and the >>>>>>> VR_INITIALIZER thing. >>>>>>> >>>>>>> You can commit the already approved refactoring changes and combine >>>>>>> this >>>>>>> patch with the struct value_range move, this way I can more easily >>>>>>> look >>>>>>> into >>>>>>> issues with the UNDEFINED thing if you can come up with a testcase >>>>>>> that >>>>>>> doesn't work. >>>>>>> >>>>>> >>>>>> I have now committed all the dependent patches. >>>>>> >>>>>> Attached patch passes regression and bootstrap except pr33738.C. This >>>>>> is an unrelated issue as discussed in >>>>>> https://gcc.gnu.org/ml/gcc-patches/2016-08/msg01386.html >>>>>> >>>>>> Is this OK? >>>>> >>>>> >>>>> >>>>> +/* Initialize local data structures for VRP. If DOM_P is true, >>>>> + we will be calling this from early_vrp where value range propagation >>>>> + is done by visiting stmts in dominator tree. ssa_propagate engine >>>>> + is not used in this case and that part of the ininitialization will >>>>> + be skipped. */ >>>>> + >>>>> +static void >>>>> +vrp_initialize () >>>>> >>>>> comment needs updating now. >>>>> >>>> Done. >>>> >>>>> >>>>> static void >>>>> -extract_range_from_phi_node (gphi *phi, value_range *vr_result) >>>>> +extract_range_from_phi_node (gphi *phi, value_range *vr_result, >>>>> + bool early_vrp_p) >>>>> { >>>>> >>>>> >>>>> I don't think you need this changes now that you have >>>>> stmt_visit_phi_node_in_dom_p >>>>> guarding its call. >>>> >>>> >>>> >>>> OK removed it. That also mean I had to put scev_* in the early_vrp. >>>> >>>> >>>> >>>>> +static bool >>>>> +stmt_visit_phi_node_in_dom_p (gphi *phi) >>>>> +{ >>>>> + ssa_op_iter iter; >>>>> + use_operand_p oprnd; >>>>> + tree op; >>>>> + value_range *vr; >>>>> + FOR_EACH_PHI_ARG (oprnd, phi, iter, SSA_OP_USE) >>>>> + { >>>>> + op = USE_FROM_PTR (oprnd); >>>>> + if (TREE_CODE (op) == SSA_NAME) >>>>> + { >>>>> + vr = get_value_range (op); >>>>> + if (vr->type == VR_UNDEFINED) >>>>> + return false; >>>>> + } >>>>> + } >>>>> >>>>> I think this is overly conservative in never allowing UNDEFINED on PHI >>>>> node args (even if the def was actually visited). I think that the most >>>>> easy way to improve this bit would be to actually track visited blocks. >>>>> You already set the EDGE_EXECUTABLE flag on edges so you could >>>>> clear BB_VISITED on all blocks and set it in the before_dom_children >>>>> hook (at the end). Then the above can be folded into the PHI visiting: >>>>> >>>>> bool has_unvisited_pred = false; >>>>> FOR_EACH_EDGE (e, ei, bb->preds) >>>>> if (!(e->src->flags & BB_VISITED)) >>>>> { >>>>> has_unvisited_preds = true; >>>>> break; >>>>> } >>>>> >>>> OK done. >>>> >>>> I also had to check for uninitialized variables that will have >>>> VR_UNDEFINED >>>> as range. We do not visit GIMPLE_NOP. >>> >>> >>> But VR_UNDEFINED of uninitialized variables is fine to use. >> >> >> Indeed. I was really trying to fix another problem with this. >> >> The real problem I am facing is: >> >> When we have a PHI stmt with one argument as symbolic VR_RANGE and another >> as VR_UNDEFINED, we will copy VR_RANGE to the PHI result. >> >> When we fold the uses of the PHI result with vrp_valueize, we will assign >> the symbol from VR_RANGE if that is of the form [a, a]. >> >> However, in replace_uses_in, we dont see if the SSA definition dominates the >> gimple that uses it. This some times results in ICE. > > Indeed -- ccp_lattice_meet avoids this by not merging UNDEF and SSA to SSA. > > VRP uses op_with_constant_singleton_value_range for the valueization at > substitute_and_fold time which only substitutes constants. > >> For now, in the vrp_valueize, I have commented out the SSA_NAME part (as >> shown in the attached patch). With that I can bootstrap and regression test >> the patch. >> >> The fix is to either: >> >> 1. Remove SSA_NAME from vrp_valueize. Currently we use vrp_valueize with >> gimple_fold_stmt_to_constant_1 and accepts only is_gimple_min_invariant. >> Therefore maybe SSA_NAME is not needed? > > Yeah, technically it is not needed. > >> 2. Or, in replace_uses_in, see if the stmt dominates operand definition >> before replacing. > > We need to treat the valueization as a "value number" and separately > keep track of available DEFs we can substitute. See for example how > FRE/PRE handle this in eliminate_dom_walker. The substitute-and-fold > DOM walker would need to be adjusted similarly (and your copy of it > in DOM VRP). > > Short-cutting this at vrp_valueize will remove some valid foldings to > constants but I think you can simply use op_with_constant_singleton_value_range > for the replace_uses_in call. > > The patch is ok with that change. Attached is the patch based on the above comments. I have marked gcc/testsuite/g++.dg/warn/pr33738.C as XFAIL and will try to fix this based on the discussion from https://gcc.gnu.org/ml/gcc-patches/2016-08/msg01386.html I will commit it after fresh bootstrap and regression testing. Thanks, Kugan > > Thanks, > Richard. > >>>> >>>>> + /* Visit PHI stmts and discover any new VRs possible. */ >>>>> + gimple_stmt_iterator gsi; >>>>> + for (gphi_iterator gpi = gsi_start_phis (bb); >>>>> + !gsi_end_p (gpi); gsi_next (&gpi)) >>>>> + { >>>>> + gphi *phi = gpi.phi (); >>>>> + tree lhs = PHI_RESULT (phi); >>>>> + value_range vr_result = VR_INITIALIZER; >>>>> + if (! has_unvisived_preds >>>>> && stmt_interesting_for_vrp (phi) >>>>> + && stmt_visit_phi_node_in_dom_p (phi)) >>> >>> >>> failed to remove this call to stmt_visit_phi_node_in_dom_p -- whether we >>> need to >>> drop to varying is a property that is the same for all PHI nodes in a >>> block. >>> >> Done. >> >>>>> + extract_range_from_phi_node (phi, &vr_result, true); >>>>> + else >>>>> + set_value_range_to_varying (&vr_result); >>>>> + update_value_range (lhs, &vr_result); >>>>> + } >>>>> >>>>> due to a bug in IRA you need to make sure to un-set BB_VISITED after >>>>> early-vrp is finished again. >>>> >>>> >>>> OK. Done. >>> >>> >>> You set BB_VISITED in after_dom_children -- that is too late, please >>> set it at the end >>> of before_dom_children. Otherwise it pessimizes handling of the PHIs >>> in the merge >>> block of a diamond in case the PHI args are defined in the immediate >>> dominator. >>> >>> As said you need to clear BB_VISITED at the start of evrp as well >>> (clearing at the end >>> is just a workaround for a IRA bug). >> >> Done. >> >>>>> >>>>> + /* Try folding stmts with the VR discovered. */ >>>>> + bool did_replace = replace_uses_in (stmt, evrp_valueize); >>>>> + if (fold_stmt (&gsi, follow_single_use_edges) >>>>> + || did_replace) >>>>> + update_stmt (gsi_stmt (gsi)); >>>>> >>>>> you should be able to re-use vrp_valueize here. >>>> >>>> >>>> This issue is vrp_valueize accepts ranges such as [VAR + CST, VAR + CST] >>>> which we can not set. >>> >>> >>> Oh - that looks like sth we need to fix anyway then. May I suggest to >>> change >>> vrp_valueize to do >>> >>> && (TREE_CODE (vr->min) == SSA_NAME >>> || is_gimple_min_invariant (TREE_CODE (vr->min))) >>> >>> which also allows [&a, &a] like constants. >> >> >> Please see the error above. >> >> >>>>> >>>>> + def_operand_p def_p = SINGLE_SSA_DEF_OPERAND (stmt, >>>>> SSA_OP_DEF); >>>>> + /* Set the SSA with the value range. */ >>>>> + if (def_p >>>>> + && TREE_CODE (DEF_FROM_PTR (def_p)) == SSA_NAME >>>>> + && INTEGRAL_TYPE_P (TREE_TYPE (DEF_FROM_PTR (def_p)))) >>>>> + { >>>>> + tree def = DEF_FROM_PTR (def_p); >>>>> + unsigned ver = SSA_NAME_VERSION (def); >>>>> + if ((vr_value[ver]->type == VR_RANGE >>>>> >>>>> Use get_value_range () please, not direct access to vr_value. >>>>> >>>> Done. >>>> >>>>> + || vr_value[ver]->type == VR_ANTI_RANGE) >>>>> + && (TREE_CODE (vr_value[ver]->min) == INTEGER_CST) >>>>> + && (TREE_CODE (vr_value[ver]->max) == INTEGER_CST)) >>>>> + set_range_info (def, vr_value[ver]->type, >>>>> vr_value[ver]->min, >>>>> + vr_value[ver]->max); >>>>> + } >>>>> >>>>> Otherwise the patch looks good now (with a lot of improvement >>>>> possibilities of course). >>>> >>>> >>>> I will work on the improvement after this goes in. >>>> >>>> Bootstrapped and regression tested on x86_64-linux-gnu. Does this looks >>>> OK? >>> >>> >>> Please remove no-op changes like >> >> Done. >> >> >>> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c >>> b/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c >>> index 7efdd63..3a433d6 100644 >>> --- a/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c >>> +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c >>> @@ -3,7 +3,7 @@ >>> known to be zero after entering the first two "if" statements. */ >>> >>> /* { dg-do compile } */ >>> -/* { dg-options "-O2 -fdump-tree-vrp1" } */ >>> +/* { dg-options "-O2 -fdump-tree-vrp1" } */ >>> >>> void link_error (void); >>> >>> @@ -21,4 +21,4 @@ foo (int *p, int q) >>> } >>> } >>> >>> -/* { dg-final { scan-tree-dump-times "Folding predicate r_.* != 0B to >>> 0" 1 "vrp1" } } */ >>> +/* { dg-final { scan-tree-dump-times "link_error" 0 "vrp1" } } */ >>> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c >>> b/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c >>> index dcf9148..c4fda8b 100644 >>> --- a/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c >>> +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr25382.c >>> @@ -3,7 +3,7 @@ >>> Check that VRP now gets ranges from BIT_AND_EXPRs. */ >>> >>> /* { dg-do compile } */ >>> -/* { dg-options "-O2 -fno-tree-ccp -fdump-tree-vrp1" } */ >>> +/* { dg-options "-O2 -fno-tree-ccp -fdump-tree-vrp" } */ >>> >>> int >>> foo (int a) >>> >>> >>> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp46.c >>> b/gcc/testsuite/gcc.dg/tree-ssa/vrp46.c >>> index d3c9ed1..5b279a1 100644 >>> --- a/gcc/testsuite/gcc.dg/tree-ssa/vrp46.c >>> +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp46.c >>> @@ -27,6 +27,5 @@ func_18 ( int t ) >>> } >>> } >>> >>> -/* There should be a single if left. */ >>> >>> -/* { dg-final { scan-tree-dump-times "if" 1 "vrp1" } } */ >>> +/* { dg-final { scan-tree-dump-times "if" 0 "vrp1" } } */ >>> >>> I'm curious -- this is not a dg-run testcase but did you investigate this >>> isn't generating wrong code now? At least I can't see how >>> the if (1 & (t % rhs)) test could vanish. >> >> Indeed.This was a mistake and fixed it. >> >> >>> I hope we'll get GIMPLE unit testing finished for GCC 7 so we can add >>> separate >>> unit-tests for VRP and EVRP. >> >> >> I will have a look at it. >> >> Thanks, >> Kugan >> >> >>> Thanks, >>> Richard. >>> >>> >>>> Thanks, >>>> Kugan >>>> >>>> >>>> >>>>> >>>>> Thanks and sorry for the delay, >>>>> Richard. >>>>> >>>>>> Thanks, >>>>>> Kugan >>>>>> >>>>>> >>>>>>> Thanks, >>>>>>> Richard. >>>>>>> >>>>>>>> I also noticed that g++.dg/warn/pr33738.C testcase is now failing. >>>>>>>> This >>>>>>>> is >>>>>>>> because, with early-vrp setting value range ccp2 is optimizing >>>>>>>> without >>>>>>>> issuing a warning. I will look into it. >>>>>>>> >>>>>>>> bootstrap and regression testing is in progress. >>>>>>>> >>>>>>>> Thanks, >>>>>>>> Kugan gcc/ChangeLog: 2016-09-20 Kugan Vivekanandarajah * doc/invoke.texi: Document -fdump-tree-evrp. * passes.def: Define new pass_early_vrp. * timevar.def: Define new TV_TREE_EARLY_VRP. * tree-pass.h (make_pass_early_vrp): New. * tree-ssa-propagate.c: Make replace_uses_in non static. * tree-ssa-propagate.h: Export replace_uses_in. * tree-vrp.c (extract_range_for_var_from_comparison_expr): New. (extract_range_from_assert): Factor out extract_range_for_var_from_comparison_expr. (vrp_initialize_lattice): New. (vrp_initialize): Factor out vrp_initialize_lattice. (vrp_valueize): Fix it to reject complex value ranges. (vrp_free_lattice): New. (evrp_dom_walker::before_dom_children): Likewise. (evrp_dom_walker::after_dom_children): Likewise. (evrp_dom_walker::push_value_range): Likewise. (evrp_dom_walker::pop_value_range): Likewise. (execute_early_vrp): Likewise. (execute_vrp): Call vrp_initialize_lattice and vrp_free_lattice. (make_pass_early_vrp): New. gcc/testsuite/ChangeLog: 2016-09-20 Kugan Vivekanandarajah * g++.dg/tree-ssa/pr31146-2.C: Run with -fno-tree-evrp as evrp also does the same transformation. * g++.dg/warn/pr33738.C: XFAIL as optimization now happens in ccp. * gcc.dg/tree-ssa/evrp1.c: New test. * gcc.dg/tree-ssa/evrp2.c: New test. * gcc.dg/tree-ssa/evrp3.c: New test. * gcc.dg/tree-ssa/pr20657.c: Check for the pattern in evrp dump. * gcc.dg/tree-ssa/pr22117.c: Likewise. * gcc.dg/tree-ssa/pr61839_2.c: Likewise. * gcc.dg/tree-ssa/pr64130.c: Likewise. * gcc.dg/tree-ssa/pr37508.c: Change the pattern to be checked as foldong now happens early. * gcc.dg/tree-ssa/vrp04.c: Likewise. * gcc.dg/tree-ssa/vrp06.c: Likewise. * gcc.dg/tree-ssa/vrp16.c: Likewise. * gcc.dg/tree-ssa/vrp25.c: Likewise. * gcc.dg/tree-ssa/vrp67.c: Likewise. >From 42cef3f7abc956ece46e4303e3a6d68464dde99c Mon Sep 17 00:00:00 2001 From: Kugan Vivekanandarajah Date: Tue, 23 Aug 2016 16:18:30 +1000 Subject: [PATCH 1/3] Add early-vrp --- gcc/doc/invoke.texi | 5 + gcc/passes.def | 1 + gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C | 2 +- gcc/testsuite/g++.dg/warn/pr33738.C | 4 +- gcc/testsuite/gcc.dg/tree-ssa/evrp1.c | 13 + gcc/testsuite/gcc.dg/tree-ssa/evrp2.c | 18 ++ gcc/testsuite/gcc.dg/tree-ssa/evrp3.c | 15 + gcc/testsuite/gcc.dg/tree-ssa/pr20657.c | 4 +- gcc/testsuite/gcc.dg/tree-ssa/pr22117.c | 2 +- gcc/testsuite/gcc.dg/tree-ssa/pr37508.c | 2 +- gcc/testsuite/gcc.dg/tree-ssa/pr61839_2.c | 8 +- gcc/testsuite/gcc.dg/tree-ssa/pr64130.c | 6 +- gcc/testsuite/gcc.dg/tree-ssa/vrp04.c | 2 +- gcc/testsuite/gcc.dg/tree-ssa/vrp06.c | 4 +- gcc/testsuite/gcc.dg/tree-ssa/vrp16.c | 4 +- gcc/testsuite/gcc.dg/tree-ssa/vrp25.c | 4 +- gcc/testsuite/gcc.dg/tree-ssa/vrp67.c | 2 +- gcc/timevar.def | 1 + gcc/tree-pass.h | 1 + gcc/tree-ssa-propagate.c | 2 +- gcc/tree-ssa-propagate.h | 1 + gcc/tree-vrp.c | 467 ++++++++++++++++++++++++++---- 22 files changed, 492 insertions(+), 76 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/evrp1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/evrp2.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/evrp3.c diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 87da1f1..9ed9c24 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -12454,6 +12454,11 @@ is made by appending @file{.slp} to the source file name. Dump each function after Value Range Propagation (VRP). The file name is made by appending @file{.vrp} to the source file name. +@item early vrp +@opindex fdump-tree-evrp +Dump each function after Early Value Range Propagation (EVRP). The file name +is made by appending @file{.evrp} to the source file name. + @item oaccdevlow @opindex fdump-tree-oaccdevlow Dump each function after applying device-specific OpenACC transformations. diff --git a/gcc/passes.def b/gcc/passes.def index 533157d..9759fed 100644 --- a/gcc/passes.def +++ b/gcc/passes.def @@ -89,6 +89,7 @@ along with GCC; see the file COPYING3. If not see execute TODO_rebuild_alias at this point. */ NEXT_PASS (pass_build_ealias); NEXT_PASS (pass_fre); + NEXT_PASS (pass_early_vrp); NEXT_PASS (pass_merge_phi); NEXT_PASS (pass_dse); NEXT_PASS (pass_cd_dce); diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C b/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C index 5e09583..cf4ed33 100644 --- a/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C +++ b/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O -fdump-tree-forwprop1" } */ +/* { dg-options "-O -fno-tree-vrp -fdump-tree-forwprop1" } */ #include diff --git a/gcc/testsuite/g++.dg/warn/pr33738.C b/gcc/testsuite/g++.dg/warn/pr33738.C index 60ee0b4..73e98d5 100644 --- a/gcc/testsuite/g++.dg/warn/pr33738.C +++ b/gcc/testsuite/g++.dg/warn/pr33738.C @@ -15,11 +15,11 @@ int GetM1() { int main() { a2 = static_cast(GetM1()); - if (a2 == -1) { // { dg-warning "always false due" } + if (a2 == -1) { // { dg-warning "always false due" "" { xfail *-*-* } } */ link_error (); } a2 = static_cast(GetM1()); - if (-1 == a2) { // { dg-warning "always false due" } + if (-1 == a2) { // { dg-warning "always false due" "" { xfail *-*-* } } */ link_error (); } return 0; diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c new file mode 100644 index 0000000..8c6e4e6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-evrp" } */ + +int foo (int i); +int bar (int j) +{ + if (j > 2) + return foo (j + 2); + else + return j; +} + +/* { dg-final { scan-tree-dump "\\\[5, \\+INF" "evrp" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp2.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp2.c new file mode 100644 index 0000000..e6d4235 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp2.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-evrp" } */ + +int foo (int i); +int bar2 (int j) +{ + if (j > 2) + { + if (j < 7) + return foo (j + 1); + else + return foo (j + 2); + } + return j; +} + + +/* { dg-final { scan-tree-dump "\\\[4, 7\\\]" "evrp" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp3.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp3.c new file mode 100644 index 0000000..1a3bbd5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp3.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-evrp" } */ + +int foo (int i); +void bar (int j) +{ + unsigned int i; + for (i = 0; i < 10; ++i) + { + bar (i + 1); + } +} + +/* { dg-final { scan-tree-dump "\\\[1, 10\\\]" "evrp" } } */ + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr20657.c b/gcc/testsuite/gcc.dg/tree-ssa/pr20657.c index 727ca4c..e678231 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/pr20657.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr20657.c @@ -3,7 +3,7 @@ statement, which was needed to eliminate the second "if" statement. */ /* { dg-do compile } */ -/* { dg-options "-O2 -fno-tree-dominator-opts -fno-tree-fre -fdump-tree-vrp1-details" } */ +/* { dg-options "-O2 -fno-tree-dominator-opts -fno-tree-fre -fdump-tree-evrp" } */ int foo (int a) @@ -14,4 +14,4 @@ foo (int a) return 0; } -/* { dg-final { scan-tree-dump-times "Folding predicate" 1 "vrp1"} } */ +/* { dg-final { scan-tree-dump-times "if" 1 "evrp"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c b/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c index 7efdd63..01cd33e 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c @@ -21,4 +21,4 @@ foo (int *p, int q) } } -/* { dg-final { scan-tree-dump-times "Folding predicate r_.* != 0B to 0" 1 "vrp1" } } */ +/* { dg-final { scan-tree-dump-times "link_error" 0 "vrp1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr37508.c b/gcc/testsuite/gcc.dg/tree-ssa/pr37508.c index 0963cd9..2ba09af 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/pr37508.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr37508.c @@ -46,4 +46,4 @@ int test4 (struct foo2 *x) return 0; } -/* { dg-final { scan-tree-dump-times "Folding" 2 "vrp1" } } */ +/* { dg-final { scan-tree-dump-times "if" 2 "vrp1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr61839_2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr61839_2.c index ffa00a7..e44dc57 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/pr61839_2.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr61839_2.c @@ -1,6 +1,6 @@ /* PR tree-optimization/61839. */ /* { dg-do compile } */ -/* { dg-options "-O2 -fdump-tree-vrp1" } */ +/* { dg-options "-O2 -fdump-tree-evrp" } */ /* { dg-require-effective-target int32plus } */ __attribute__ ((noinline)) @@ -47,8 +47,8 @@ int bar2 () /* Dont optimize 972195717 / 0 in function foo. */ -/* { dg-final { scan-tree-dump-times "972195717 / _" 1 "vrp1" } } */ +/* { dg-final { scan-tree-dump-times "972195717 / _" 1 "evrp" } } */ /* Dont optimize 972195717 % 0 in function bar. */ -/* { dg-final { scan-tree-dump-times "972195717 % _" 1 "vrp1" } } */ +/* { dg-final { scan-tree-dump-times "972195717 % _" 1 "evrp" } } */ /* Optimize in function bar2. */ -/* { dg-final { scan-tree-dump-times "972195715 % _" 0 "vrp1" } } */ +/* { dg-final { scan-tree-dump-times "972195715 % _" 0 "evrp" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr64130.c b/gcc/testsuite/gcc.dg/tree-ssa/pr64130.c index 0b25466..f39bd17 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/pr64130.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr64130.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fdump-tree-vrp1" } */ +/* { dg-options "-O2 -fdump-tree-evrp" } */ int funsigned (unsigned a) { @@ -13,6 +13,6 @@ int funsigned2 (unsigned a) return (-1 * 0x1ffffffffL) / a == 0; } -/* { dg-final { scan-tree-dump ": \\\[2, 8589934591\\\]" "vrp1" } } */ -/* { dg-final { scan-tree-dump ": \\\[-8589934591, -2\\\]" "vrp1" } } */ +/* { dg-final { scan-tree-dump ": \\\[2, 8589934591\\\]" "evrp" } } */ +/* { dg-final { scan-tree-dump ": \\\[-8589934591, -2\\\]" "evrp" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp04.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp04.c index 61b7a47..67f8f01 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/vrp04.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp04.c @@ -10,4 +10,4 @@ foo (int a, int b) return a + b; } -/* { dg-final { scan-tree-dump-times "Folding predicate a_.*to 1" 1 "vrp1" } } */ +/* { dg-final { scan-tree-dump-times "if" 1 "vrp1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp06.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp06.c index cdad534..c4ce170 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/vrp06.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp06.c @@ -28,6 +28,6 @@ foo (int i, int j, int a) return i + a + j; } -/* { dg-final { scan-tree-dump-times "Folding predicate i_\[0-9\]+.*0 to 0" 1 "vrp1" } } */ -/* { dg-final { scan-tree-dump-times "Folding predicate j_\[0-9\]+.*0 to 1" 1 "vrp1" } } */ +/* { dg-final { scan-tree-dump-times "Folding predicate \[i|j\]_\[0-9\]+.*0 to 0" 1 "vrp1" } } */ +/* { dg-final { scan-tree-dump-times "Folding predicate \[i|j\]_\[0-9\]+.*0 to 1" 1 "vrp1" } } */ /* { dg-final { scan-tree-dump-times "Folding predicate i_\[0-9]+.*j_\[0-9\]+.* to 0" 1 "vrp1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp16.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp16.c index 8f5d5c8..d09f3ae 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/vrp16.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp16.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fno-tree-fre -fdump-tree-vrp1-details" } */ +/* { dg-options "-O2 -fno-tree-fre -fdump-tree-evrp" } */ extern void abort (void) __attribute__ ((__noreturn__)); @@ -19,5 +19,5 @@ nonlocal_mentioned_p (rtx x) abort (); } -/* { dg-final { scan-tree-dump-times "Folding predicate .*to 0" 1 "vrp1" } } */ +/* { dg-final { scan-tree-dump-times "if" 0 "evrp" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp25.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp25.c index cbc4ec3..a49f079 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/vrp25.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp25.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fno-tree-fre -fdump-tree-vrp1-details" } */ +/* { dg-options "-O2 -fno-tree-fre -fdump-tree-vrp1" } */ extern void abort (); extern void arf (); @@ -49,5 +49,5 @@ L9: /* The second test of (code1 != 53) and the test (D18670 <= 2) are both totally subsumed by earlier tests and thus should be folded away using VRP. */ -/* { dg-final { scan-tree-dump-times "Folding predicate" 2 "vrp1" } } */ +/* { dg-final { scan-tree-dump-times "if" 3 "vrp1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c index ef5e8f9..5155f7b 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c @@ -36,4 +36,4 @@ unsigned baz (unsigned i) return i; } -/* { dg-final { scan-tree-dump-times "Folding predicate" 3 "vrp1" } } */ +/* { dg-final { scan-tree-dump-times "if" 3 "vrp1" } } */ diff --git a/gcc/timevar.def b/gcc/timevar.def index 5f12118..8837832 100644 --- a/gcc/timevar.def +++ b/gcc/timevar.def @@ -149,6 +149,7 @@ DEFTIMEVAR (TV_TREE_CFG , "tree CFG construction") DEFTIMEVAR (TV_TREE_CLEANUP_CFG , "tree CFG cleanup") DEFTIMEVAR (TV_TREE_TAIL_MERGE , "tree tail merge") DEFTIMEVAR (TV_TREE_VRP , "tree VRP") +DEFTIMEVAR (TV_TREE_EARLY_VRP , "tree Early VRP") DEFTIMEVAR (TV_TREE_COPY_PROP , "tree copy propagation") DEFTIMEVAR (TV_FIND_REFERENCED_VARS , "tree find ref. vars") DEFTIMEVAR (TV_TREE_PTA , "tree PTA") diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index c0059de..86d797e 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -440,6 +440,7 @@ extern gimple_opt_pass *make_pass_fre (gcc::context *ctxt); extern gimple_opt_pass *make_pass_check_data_deps (gcc::context *ctxt); extern gimple_opt_pass *make_pass_copy_prop (gcc::context *ctxt); extern gimple_opt_pass *make_pass_isolate_erroneous_paths (gcc::context *ctxt); +extern gimple_opt_pass *make_pass_early_vrp (gcc::context *ctxt); extern gimple_opt_pass *make_pass_vrp (gcc::context *ctxt); extern gimple_opt_pass *make_pass_uncprop (gcc::context *ctxt); extern gimple_opt_pass *make_pass_return_slot (gcc::context *ctxt); diff --git a/gcc/tree-ssa-propagate.c b/gcc/tree-ssa-propagate.c index c8cf078..97cfde5 100644 --- a/gcc/tree-ssa-propagate.c +++ b/gcc/tree-ssa-propagate.c @@ -863,7 +863,7 @@ static struct prop_stats_d prop_stats; /* Replace USE references in statement STMT with the values stored in PROP_VALUE. Return true if at least one reference was replaced. */ -static bool +bool replace_uses_in (gimple *stmt, ssa_prop_get_value_fn get_value) { bool replaced = false; diff --git a/gcc/tree-ssa-propagate.h b/gcc/tree-ssa-propagate.h index 30d66a9..1a96976 100644 --- a/gcc/tree-ssa-propagate.h +++ b/gcc/tree-ssa-propagate.h @@ -84,5 +84,6 @@ extern void propagate_value (use_operand_p, tree); extern void replace_exp (use_operand_p, tree); extern void propagate_tree_value (tree *, tree); extern void propagate_tree_value_into_stmt (gimple_stmt_iterator *, tree); +extern bool replace_uses_in (gimple *stmt, ssa_prop_get_value_fn get_value); #endif /* _TREE_SSA_PROPAGATE_H */ diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index 45882c4..c8481c9 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -60,6 +60,8 @@ along with GCC; see the file COPYING3. If not see #include "case-cfn-macros.h" #include "params.h" #include "alloc-pool.h" +#include "domwalk.h" +#include "tree-cfgcleanup.h" #define VR_INITIALIZER { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL } @@ -1455,44 +1457,17 @@ op_with_boolean_value_range_p (tree op) && integer_onep (vr->max)); } -/* Extract value range information from an ASSERT_EXPR EXPR and store - it in *VR_P. */ +/* Extract value range information for VAR when (OP COND_CODE LIMIT) is + true and store it in *VR_P. */ static void -extract_range_from_assert (value_range *vr_p, tree expr) +extract_range_for_var_from_comparison_expr (tree var, enum tree_code cond_code, + tree op, tree limit, + value_range *vr_p) { - tree var, cond, limit, min, max, type; + tree min, max, type; value_range *limit_vr; - enum tree_code cond_code; - - var = ASSERT_EXPR_VAR (expr); - cond = ASSERT_EXPR_COND (expr); - - gcc_assert (COMPARISON_CLASS_P (cond)); - - /* Find VAR in the ASSERT_EXPR conditional. */ - if (var == TREE_OPERAND (cond, 0) - || TREE_CODE (TREE_OPERAND (cond, 0)) == PLUS_EXPR - || TREE_CODE (TREE_OPERAND (cond, 0)) == NOP_EXPR) - { - /* If the predicate is of the form VAR COMP LIMIT, then we just - take LIMIT from the RHS and use the same comparison code. */ - cond_code = TREE_CODE (cond); - limit = TREE_OPERAND (cond, 1); - cond = TREE_OPERAND (cond, 0); - } - else - { - /* If the predicate is of the form LIMIT COMP VAR, then we need - to flip around the comparison code to create the proper range - for VAR. */ - cond_code = swap_tree_comparison (TREE_CODE (cond)); - limit = TREE_OPERAND (cond, 0); - cond = TREE_OPERAND (cond, 1); - } - limit = avoid_overflow_infinity (limit); - type = TREE_TYPE (var); gcc_assert (limit != var); @@ -1538,15 +1513,15 @@ extract_range_from_assert (value_range *vr_p, tree expr) as well build the range [b_4, +INF] for it. One special case we handle is extracting a range from a range test encoded as (unsigned)var + CST <= limit. */ - if (TREE_CODE (cond) == NOP_EXPR - || TREE_CODE (cond) == PLUS_EXPR) + if (TREE_CODE (op) == NOP_EXPR + || TREE_CODE (op) == PLUS_EXPR) { - if (TREE_CODE (cond) == PLUS_EXPR) + if (TREE_CODE (op) == PLUS_EXPR) { - min = fold_build1 (NEGATE_EXPR, TREE_TYPE (TREE_OPERAND (cond, 1)), - TREE_OPERAND (cond, 1)); + min = fold_build1 (NEGATE_EXPR, TREE_TYPE (TREE_OPERAND (op, 1)), + TREE_OPERAND (op, 1)); max = int_const_binop (PLUS_EXPR, limit, min); - cond = TREE_OPERAND (cond, 0); + op = TREE_OPERAND (op, 0); } else { @@ -1730,6 +1705,41 @@ extract_range_from_assert (value_range *vr_p, tree expr) vrp_intersect_ranges (vr_p, get_value_range (var)); } +/* Extract value range information from an ASSERT_EXPR EXPR and store + it in *VR_P. */ + +static void +extract_range_from_assert (value_range *vr_p, tree expr) +{ + tree var = ASSERT_EXPR_VAR (expr); + tree cond = ASSERT_EXPR_COND (expr); + tree limit, op; + enum tree_code cond_code; + gcc_assert (COMPARISON_CLASS_P (cond)); + + /* Find VAR in the ASSERT_EXPR conditional. */ + if (var == TREE_OPERAND (cond, 0) + || TREE_CODE (TREE_OPERAND (cond, 0)) == PLUS_EXPR + || TREE_CODE (TREE_OPERAND (cond, 0)) == NOP_EXPR) + { + /* If the predicate is of the form VAR COMP LIMIT, then we just + take LIMIT from the RHS and use the same comparison code. */ + cond_code = TREE_CODE (cond); + limit = TREE_OPERAND (cond, 1); + op = TREE_OPERAND (cond, 0); + } + else + { + /* If the predicate is of the form LIMIT COMP VAR, then we need + to flip around the comparison code to create the proper range + for VAR. */ + cond_code = swap_tree_comparison (TREE_CODE (cond)); + limit = TREE_OPERAND (cond, 0); + op = TREE_OPERAND (cond, 1); + } + extract_range_for_var_from_comparison_expr (var, cond_code, op, + limit, vr_p); +} /* Extract range information from SSA name VAR and store it in VR. If VAR has an interesting range, use it. Otherwise, create the @@ -6947,19 +6957,24 @@ stmt_interesting_for_vrp (gimple *stmt) return false; } - -/* Initialize local data structures for VRP. */ +/* Initialize VRP lattice. */ static void -vrp_initialize (void) +vrp_initialize_lattice () { - basic_block bb; - values_propagated = false; num_vr_values = num_ssa_names; vr_value = XCNEWVEC (value_range *, num_vr_values); vr_phi_edge_counts = XCNEWVEC (int, num_ssa_names); bitmap_obstack_initialize (&vrp_equiv_obstack); +} + +/* Initialization required by ssa_propagate engine. */ + +static void +vrp_initialize () +{ + basic_block bb; FOR_EACH_BB_FN (bb, cfun) { @@ -7010,6 +7025,8 @@ vrp_valueize (tree name) { value_range *vr = get_value_range (name); if (vr->type == VR_RANGE + && (TREE_CODE (vr->min) == SSA_NAME + || is_gimple_min_invariant (vr->min)) && vrp_operand_equal_p (vr->min, vr->max)) return vr->min; } @@ -10500,6 +10517,22 @@ finalize_jump_threads (void) delete equiv_stack; } +/* Free VRP lattice. */ + +static void +vrp_free_lattice () +{ + /* Free allocated memory. */ + free (vr_value); + free (vr_phi_edge_counts); + bitmap_obstack_release (&vrp_equiv_obstack); + vrp_value_range_pool.release (); + + /* So that we can distinguish between VRP data being available + and not available. */ + vr_value = NULL; + vr_phi_edge_counts = NULL; +} /* Traverse all the blocks folding conditionals with known ranges. */ @@ -10546,17 +10579,302 @@ vrp_finalize (bool warn_array_bounds_p) /* We must identify jump threading opportunities before we release the datastructures built by VRP. */ identify_jump_threads (); +} - /* Free allocated memory. */ - free (vr_value); - free (vr_phi_edge_counts); - bitmap_obstack_release (&vrp_equiv_obstack); - vrp_value_range_pool.release (); +/* evrp_dom_walker visits the basic blocks in the dominance order and set + the Value Ranges (VR) for SSA_NAMEs in the scope. Use this VR to + discover more VRs. */ - /* So that we can distinguish between VRP data being available - and not available. */ - vr_value = NULL; - vr_phi_edge_counts = NULL; +class evrp_dom_walker : public dom_walker +{ +public: + evrp_dom_walker () + : dom_walker (CDI_DOMINATORS), stack (10) + { + stmts_to_fixup.create (0); + need_eh_cleanup = BITMAP_ALLOC (NULL); + } + ~evrp_dom_walker () + { + stmts_to_fixup.release (); + BITMAP_FREE (need_eh_cleanup); + } + virtual edge before_dom_children (basic_block); + virtual void after_dom_children (basic_block); + void push_value_range (const_tree var, value_range *vr); + value_range *pop_value_range (const_tree var); + + /* Cond_stack holds the old VR. */ + auto_vec > stack; + bitmap need_eh_cleanup; + vec stmts_to_fixup; +}; + +/* See if there is any new scope is entered with new VR and set that VR to + ssa_name before visiting the statements in the scope. */ + +edge +evrp_dom_walker::before_dom_children (basic_block bb) +{ + value_range *new_vr = NULL; + tree op0 = NULL_TREE; + + push_value_range (NULL_TREE, NULL); + if (single_pred_p (bb)) + { + edge e = single_pred_edge (bb); + value_range vr = VR_INITIALIZER; + gimple *stmt = last_stmt (e->src); + if (stmt + && gimple_code (stmt) == GIMPLE_COND + && (op0 = gimple_cond_lhs (stmt)) + && TREE_CODE (op0) == SSA_NAME + && INTEGRAL_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt)))) + { + /* Entering a new scope. Try to see if we can find a VR + here. */ + tree op1 = gimple_cond_rhs (stmt); + tree_code code = gimple_cond_code (stmt); + value_range *old_vr = get_value_range (op0); + + if (TREE_OVERFLOW_P (op1)) + op1 = drop_tree_overflow (op1); + + /* If condition is false, invert the cond. */ + if (e->flags & EDGE_FALSE_VALUE) + code = invert_tree_comparison (gimple_cond_code (stmt), + HONOR_NANS (op0)); + /* Discover VR when condition is true. */ + extract_range_for_var_from_comparison_expr (op0, code, op0, op1, &vr); + if (old_vr->type == VR_RANGE || old_vr->type == VR_ANTI_RANGE) + vrp_intersect_ranges (&vr, old_vr); + + /* If we found any usable VR, set the VR to ssa_name and create a + PUSH old value in the stack with the old VR. */ + if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE) + { + new_vr = vrp_value_range_pool.allocate (); + *new_vr = vr; + push_value_range (op0, new_vr); + } + } + } + + /* Visit PHI stmts and discover any new VRs possible. */ + gimple_stmt_iterator gsi; + edge e; + edge_iterator ei; + bool has_unvisived_preds = false; + + FOR_EACH_EDGE (e, ei, bb->preds) + if (!(e->src->flags & BB_VISITED)) + { + has_unvisived_preds = true; + break; + } + + for (gphi_iterator gpi = gsi_start_phis (bb); + !gsi_end_p (gpi); gsi_next (&gpi)) + { + gphi *phi = gpi.phi (); + tree lhs = PHI_RESULT (phi); + value_range vr_result = VR_INITIALIZER; + if (!has_unvisived_preds + && stmt_interesting_for_vrp (phi)) + extract_range_from_phi_node (phi, &vr_result); + else + set_value_range_to_varying (&vr_result); + update_value_range (lhs, &vr_result); + } + + /* Visit all other stmts and discover any new VRs possible. */ + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple *stmt = gsi_stmt (gsi); + edge taken_edge; + tree output = NULL_TREE; + gimple *old_stmt = stmt; + bool was_noreturn = (is_gimple_call (stmt) + && gimple_call_noreturn_p (stmt)); + + /* TODO, if found taken_edge, we should visit (return it) and travel + again to improve VR as done in DOM/SCCVN optimizations. It should + be done carefully as stmts might prematurely leave a BB like + in EH. */ + if (stmt_interesting_for_vrp (stmt)) + { + value_range vr = VR_INITIALIZER; + extract_range_from_stmt (stmt, &taken_edge, &output, &vr); + if (output + && (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE)) + update_value_range (output, &vr); + else + { + tree def; + ssa_op_iter iter; + FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_DEF) + set_value_range_to_varying (get_value_range (def)); + } + + /* Try folding stmts with the VR discovered. */ + bool did_replace + = replace_uses_in (stmt, + op_with_constant_singleton_value_range); + if (fold_stmt (&gsi, follow_single_use_edges) + || did_replace) + update_stmt (gsi_stmt (gsi)); + + if (did_replace) + { + /* If we cleaned up EH information from the statement, + remove EH edges. */ + if (maybe_clean_or_replace_eh_stmt (old_stmt, stmt)) + bitmap_set_bit (need_eh_cleanup, bb->index); + + /* If we turned a not noreturn call into a noreturn one + schedule it for fixup. */ + if (!was_noreturn + && is_gimple_call (stmt) + && gimple_call_noreturn_p (stmt)) + stmts_to_fixup.safe_push (stmt); + + if (gimple_assign_single_p (stmt)) + { + tree rhs = gimple_assign_rhs1 (stmt); + if (TREE_CODE (rhs) == ADDR_EXPR) + recompute_tree_invariant_for_addr_expr (rhs); + } + } + + def_operand_p def_p = SINGLE_SSA_DEF_OPERAND (stmt, SSA_OP_DEF); + /* Set the SSA with the value range. */ + if (def_p + && TREE_CODE (DEF_FROM_PTR (def_p)) == SSA_NAME + && INTEGRAL_TYPE_P (TREE_TYPE (DEF_FROM_PTR (def_p)))) + { + tree def = DEF_FROM_PTR (def_p); + value_range *vr = get_value_range (def); + + if ((vr->type == VR_RANGE + || vr->type == VR_ANTI_RANGE) + && (TREE_CODE (vr->min) == INTEGER_CST) + && (TREE_CODE (vr->max) == INTEGER_CST)) + set_range_info (def, vr->type, vr->min, vr->max); + } + } + else + { + tree def; + ssa_op_iter iter; + FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_DEF) + set_value_range_to_varying (get_value_range (def)); + } + } + bb->flags |= BB_VISITED; + return NULL; +} + +/* Restore/pop VRs valid only for BB when we leave BB. */ + +void +evrp_dom_walker::after_dom_children (basic_block bb ATTRIBUTE_UNUSED) +{ + gcc_checking_assert (!stack.is_empty ()); + while (stack.last ().first != NULL_TREE) + pop_value_range (stack.last ().first); + pop_value_range (stack.last ().first); +} + +/* Push the Value Range of VAR to the stack and update it with new VR. */ + +void +evrp_dom_walker::push_value_range (const_tree var, value_range *vr) +{ + if (vr != NULL) + { + unsigned ver = SSA_NAME_VERSION (var); + gcc_checking_assert (vr_value); + stack.safe_push (std::make_pair (var, vr_value[ver])); + + if (ver < num_vr_values) + vr_value[ver] = vr; + } + else + stack.safe_push (std::make_pair (var, vr)); +} + +/* Pop the Value Range from the vrp_stack and update VAR with it. */ + +value_range * +evrp_dom_walker::pop_value_range (const_tree var) +{ + value_range *vr = stack.last ().second; + if (vr != NULL) + { + unsigned ver = SSA_NAME_VERSION (var); + gcc_checking_assert (var == stack.last ().first); + gcc_checking_assert (vr_value); + + if (ver < num_vr_values) + vr_value[ver] = vr; + } + stack.pop (); + return vr; +} + + +/* Main entry point for the early vrp pass which is a simplified non-iterative + version of vrp where basic blocks are visited in dominance order. Value + ranges discovered in early vrp will also be used by ipa-vrp. */ + +static unsigned int +execute_early_vrp () +{ + edge e; + edge_iterator ei; + basic_block bb; + + loop_optimizer_init (LOOPS_NORMAL | LOOPS_HAVE_RECORDED_EXITS); + rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa); + scev_initialize (); + calculate_dominance_info (CDI_DOMINATORS); + FOR_EACH_BB_FN (bb, cfun) + { + bb->flags &= ~BB_VISITED; + FOR_EACH_EDGE (e, ei, bb->preds) + e->flags |= EDGE_EXECUTABLE; + } + vrp_initialize_lattice (); + + /* Walk stmts in dominance order and propagate VRP. */ + evrp_dom_walker walker; + walker.walk (ENTRY_BLOCK_PTR_FOR_FN (cfun)); + + if (!bitmap_empty_p (walker.need_eh_cleanup)) + gimple_purge_all_dead_eh_edges (walker.need_eh_cleanup); + + /* Fixup stmts that became noreturn calls. This may require splitting + blocks and thus isn't possible during the dominator walk. Do this + in reverse order so we don't inadvertedly remove a stmt we want to + fixup by visiting a dominating now noreturn call first. */ + while (!walker.stmts_to_fixup.is_empty ()) + { + gimple *stmt = walker.stmts_to_fixup.pop (); + fixup_noreturn_call (stmt); + } + + if (dump_file) + { + fprintf (dump_file, "\nValue ranges after Early VRP:\n\n"); + dump_all_value_ranges (dump_file); + fprintf (dump_file, "\n"); + } + vrp_free_lattice (); + scev_finalize (); + loop_optimizer_finalize (); + FOR_EACH_BB_FN (bb, cfun) + bb->flags &= ~BB_VISITED; + return 0; } @@ -10627,9 +10945,11 @@ execute_vrp (bool warn_array_bounds_p) /* For visiting PHI nodes we need EDGE_DFS_BACK computed. */ mark_dfs_back_edges (); + vrp_initialize_lattice (); vrp_initialize (); ssa_propagate (vrp_visit_stmt, vrp_visit_phi_node); vrp_finalize (warn_array_bounds_p); + vrp_free_lattice (); free_numbers_of_iterations_estimates (cfun); @@ -10727,3 +11047,44 @@ make_pass_vrp (gcc::context *ctxt) { return new pass_vrp (ctxt); } + +namespace { + +const pass_data pass_data_early_vrp = +{ + GIMPLE_PASS, /* type */ + "evrp", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + TV_TREE_EARLY_VRP, /* tv_id */ + PROP_ssa, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + ( TODO_cleanup_cfg | TODO_update_ssa | TODO_verify_all ), +}; + +class pass_early_vrp : public gimple_opt_pass +{ +public: + pass_early_vrp (gcc::context *ctxt) + : gimple_opt_pass (pass_data_early_vrp, ctxt) + {} + + /* opt_pass methods: */ + opt_pass * clone () { return new pass_early_vrp (m_ctxt); } + virtual bool gate (function *) + { + return flag_tree_vrp != 0; + } + virtual unsigned int execute (function *) + { return execute_early_vrp (); } + +}; // class pass_vrp +} // anon namespace + +gimple_opt_pass * +make_pass_early_vrp (gcc::context *ctxt) +{ + return new pass_early_vrp (ctxt); +} + -- 2.7.4