diff mbox

[RFC,IPA-VRP] Early VRP Implementation

Message ID CAELXzTNiYLRn0T70mi6K27H7Tt9AQNYyYamJ99di3vWtivLGbw@mail.gmail.com
State New
Headers show

Commit Message

Kugan Vivekanandarajah Aug. 23, 2016, 2:11 a.m. UTC
Hi,

On 19 August 2016 at 21:41, Richard Biener <richard.guenther@gmail.com> wrote:
> On Tue, Aug 16, 2016 at 9:45 AM, kugan
> <kugan.vivekanandarajah@linaro.org> wrote:
>> Hi Richard,
>>
>> On 12/08/16 20:43, Richard Biener wrote:
>>>
>>> On Wed, Aug 3, 2016 at 3:17 AM, kugan <kugan.vivekanandarajah@linaro.org>
>>> wrote:
>>
>>
>> [SNIP]
>>
>>>
>>> diff --git a/gcc/common.opt b/gcc/common.opt
>>> index 8a292ed..7028cd4 100644
>>> --- a/gcc/common.opt
>>> +++ b/gcc/common.opt
>>> @@ -2482,6 +2482,10 @@ ftree-vrp
>>>  Common Report Var(flag_tree_vrp) Init(0) Optimization
>>>  Perform Value Range Propagation on trees.
>>>
>>> +fdisable-tree-evrp
>>> +Common Report Var(flag_disable_early_vrp) Init(0) Optimization
>>> +Disable Early Value Range Propagation on trees.
>>> +
>>>
>>> no please, this is automatically supported via -fdisable-
>>
>>
>> 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.

>>>
>>> @@ -1728,11 +1736,12 @@ extract_range_from_assert (value_range *vr_p, tree
>>> expr)
>>>      always false.  */
>>>
>>>  static void
>>> -extract_range_from_ssa_name (value_range *vr, tree var)
>>> +extract_range_from_ssa_name (value_range *vr, bool dom_p, tree var)
>>>  {
>>>    value_range *var_vr = get_value_range (var);
>>>
>>> -  if (var_vr->type != VR_VARYING)
>>> +  if (var_vr->type != VR_VARYING
>>> +      && (!dom_p || var_vr->type != VR_UNDEFINED))
>>>      copy_value_range (vr, var_vr);
>>>    else
>>>      set_value_range (vr, VR_RANGE, var, var, NULL);
>>>
>>> why do you need these changes?  I think I already told you you need to
>>> initialize the lattice to sth else than VR_UNDEFINED and that you can't
>>> fully re-use update_value_range.  If you don't want to do that then
>>> instead
>>> of doing changes all over the place do it in get_value_range and have a
>>> global flag.
>>
>>
>> I have now added a global early_vrp_p and use this to initialize
>> VR_INITIALIZER and get_value_range default to VR_VARYING.
>
> ICK.  Ok, I see that this works, but it is quite ugly, so (see below)
>
>>>
>>>
>>> @@ -3594,7 +3643,8 @@ extract_range_from_cond_expr (value_range *vr,
>>> gassign *stmt)
>>>     on the range of its operand and the expression code.  */
>>>
>>>  static void
>>> -extract_range_from_comparison (value_range *vr, enum tree_code code,
>>> +extract_range_from_comparison (value_range *vr,
>>> +                              enum tree_code code,
>>>                                tree type, tree op0, tree op1)
>>>  {
>>>    bool sop = false;
>>>
>>> remove these kind of no-op changes.
>>
>>
>> Done.
>>
>>
>>>
>>> +/* 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 (void)
>>> +vrp_initialize (bool dom_p)
>>>  {
>>>    basic_block bb;
>>>
>>> @@ -6949,6 +7010,9 @@ vrp_initialize (void)
>>>    vr_phi_edge_counts = XCNEWVEC (int, num_ssa_names);
>>>    bitmap_obstack_initialize (&vrp_equiv_obstack);
>>>
>>> +  if (dom_p)
>>> +    return;
>>> +
>>>
>>> split the function instead.
>>>
>>> @@ -7926,7 +7992,8 @@ vrp_visit_switch_stmt (gswitch *stmt, edge
>>> *taken_edge_p)
>>>     If STMT produces a varying value, return SSA_PROP_VARYING.  */
>>>
>>>  static enum ssa_prop_result
>>> -vrp_visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
>>> +vrp_visit_stmt_worker (gimple *stmt, bool dom_p,  edge *taken_edge_p,
>>> +                      tree *output_p)
>>>  {
>>>    tree def;
>>>    ssa_op_iter iter;
>>> @@ -7940,7 +8007,7 @@ vrp_visit_stmt (gimple *stmt, edge
>>> *taken_edge_p, tree *output_p)
>>>    if (!stmt_interesting_for_vrp (stmt))
>>>      gcc_assert (stmt_ends_bb_p (stmt));
>>>    else if (is_gimple_assign (stmt) || is_gimple_call (stmt))
>>> -    return vrp_visit_assignment_or_call (stmt, output_p);
>>> +    return vrp_visit_assignment_or_call (stmt, dom_p, output_p);
>>>    else if (gimple_code (stmt) == GIMPLE_COND)
>>>      return vrp_visit_cond_stmt (as_a <gcond *> (stmt), taken_edge_p);
>>>    else if (gimple_code (stmt) == GIMPLE_SWITCH)
>>> @@ -7954,6 +8021,12 @@ vrp_visit_stmt (gimple *stmt, edge
>>> *taken_edge_p, tree *output_p)
>>>    return SSA_PROP_VARYING;
>>>  }
>>>
>>> +static enum ssa_prop_result
>>> +vrp_visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
>>> +{
>>> +  return vrp_visit_stmt_worker (stmt, false, taken_edge_p, output_p);
>>> +}
>>>
>>> as said the refactoring that would be appreciated is to split out the
>>> update_value_range calls
>>> from the worker functions so you can call the respective functions
>>> from the DOM implementations.
>>> That they are globbed in vrp_visit_stmt currently is due to the API of
>>> the SSA propagator.
>>
>> Sent this as separate patch for easy reviewing and testing.
>
> Thanks.
>
>>>
>>> @@ -8768,6 +8842,12 @@ vrp_visit_phi_node (gphi *phi)
>>>               fprintf (dump_file, "\n");
>>>             }
>>>
>>> +         if (dom_p && vr_arg.type == VR_UNDEFINED)
>>> +           {
>>> +             set_value_range_to_varying (&vr_result);
>>> +             break;
>>> +           }
>>> +
>>>
>>> eh...  ok, so another way to attack this is, instead of initializing
>>> the lattice to sth else
>>> than VR_UNDEFINED, make sure to drop the lattice to varying for all PHI
>>> args on
>>> yet unvisited incoming edges (you're not doing optimistic VRP).  That's
>>> the only
>>> place you _have_ to do it.
>>
>>
>> Even when it is initialize (as I am doing now), we can still end up with
>> VR_UNDEFINED during the propagation.  I have just left the above so that we
>> dont end up with the wrong VR.
>
> How would we end up with wrong VRs?  I see
>
> +         /* 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);
>
> where you already disregard UNDEFINED as old_vr.
>
> What you might be missing is to set all DEFs on !stmt_interesting_for_vrp to
> VARYING.  Also
>
> +      if (stmt_interesting_for_vrp (stmt))
> +       {
> +         tree lhs = gimple_get_lhs (stmt);
> +         value_range vr = VR_INITIALIZER;
> +         vrp_visit_stmt_worker (stmt, &taken_edge, &output, &vr);
> +         update_value_range (lhs, &vr);
> +
> +         /* Try folding stmts with the VR discovered.  */
> +         if (fold_stmt (&gsi, follow_single_use_edges))
> +           update_stmt (gsi_stmt (gsi));
>
> folding here can introduce additional stmts and thus unvisited SSA defs
> which would end up with VR_UNINITIALIZED defs - I don't see exactly
> where that would cause issues but I'm not sure it might not.  So better
> use fold_stmt_inplace or alternatively if fold_stmt returned true then,
> remembering the previous stmt gsi, iterate over all stmts emitted and
> set their defs to varying (or re-visit them).  See for example how
> tree-ssa-forwprop.c does this re-visiting (it revisits all changed stmts).

I am now setting the results of stmts that are not interesting to vrp
to VR_VARYING.

Also, before visiting PHI, if any of the arguments are undefined,
result of the PHI is also set varying.

I have removed all the others. This now bootstraps and passes
regressions (see attached patch).


> 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.

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?

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

Comments

Kugan Vivekanandarajah Sept. 2, 2016, 8:11 a.m. UTC | #1
Ping ?

Thanks,
Kugan

On 23 August 2016 at 12:11, Kugan Vivekanandarajah
<kugan.vivekanandarajah@linaro.org> wrote:
> Hi,
>
> On 19 August 2016 at 21:41, Richard Biener <richard.guenther@gmail.com> wrote:
>> On Tue, Aug 16, 2016 at 9:45 AM, kugan
>> <kugan.vivekanandarajah@linaro.org> wrote:
>>> Hi Richard,
>>>
>>> On 12/08/16 20:43, Richard Biener wrote:
>>>>
>>>> On Wed, Aug 3, 2016 at 3:17 AM, kugan <kugan.vivekanandarajah@linaro.org>
>>>> wrote:
>>>
>>>
>>> [SNIP]
>>>
>>>>
>>>> diff --git a/gcc/common.opt b/gcc/common.opt
>>>> index 8a292ed..7028cd4 100644
>>>> --- a/gcc/common.opt
>>>> +++ b/gcc/common.opt
>>>> @@ -2482,6 +2482,10 @@ ftree-vrp
>>>>  Common Report Var(flag_tree_vrp) Init(0) Optimization
>>>>  Perform Value Range Propagation on trees.
>>>>
>>>> +fdisable-tree-evrp
>>>> +Common Report Var(flag_disable_early_vrp) Init(0) Optimization
>>>> +Disable Early Value Range Propagation on trees.
>>>> +
>>>>
>>>> no please, this is automatically supported via -fdisable-
>>>
>>>
>>> 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.
>
>>>>
>>>> @@ -1728,11 +1736,12 @@ extract_range_from_assert (value_range *vr_p, tree
>>>> expr)
>>>>      always false.  */
>>>>
>>>>  static void
>>>> -extract_range_from_ssa_name (value_range *vr, tree var)
>>>> +extract_range_from_ssa_name (value_range *vr, bool dom_p, tree var)
>>>>  {
>>>>    value_range *var_vr = get_value_range (var);
>>>>
>>>> -  if (var_vr->type != VR_VARYING)
>>>> +  if (var_vr->type != VR_VARYING
>>>> +      && (!dom_p || var_vr->type != VR_UNDEFINED))
>>>>      copy_value_range (vr, var_vr);
>>>>    else
>>>>      set_value_range (vr, VR_RANGE, var, var, NULL);
>>>>
>>>> why do you need these changes?  I think I already told you you need to
>>>> initialize the lattice to sth else than VR_UNDEFINED and that you can't
>>>> fully re-use update_value_range.  If you don't want to do that then
>>>> instead
>>>> of doing changes all over the place do it in get_value_range and have a
>>>> global flag.
>>>
>>>
>>> I have now added a global early_vrp_p and use this to initialize
>>> VR_INITIALIZER and get_value_range default to VR_VARYING.
>>
>> ICK.  Ok, I see that this works, but it is quite ugly, so (see below)
>>
>>>>
>>>>
>>>> @@ -3594,7 +3643,8 @@ extract_range_from_cond_expr (value_range *vr,
>>>> gassign *stmt)
>>>>     on the range of its operand and the expression code.  */
>>>>
>>>>  static void
>>>> -extract_range_from_comparison (value_range *vr, enum tree_code code,
>>>> +extract_range_from_comparison (value_range *vr,
>>>> +                              enum tree_code code,
>>>>                                tree type, tree op0, tree op1)
>>>>  {
>>>>    bool sop = false;
>>>>
>>>> remove these kind of no-op changes.
>>>
>>>
>>> Done.
>>>
>>>
>>>>
>>>> +/* 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 (void)
>>>> +vrp_initialize (bool dom_p)
>>>>  {
>>>>    basic_block bb;
>>>>
>>>> @@ -6949,6 +7010,9 @@ vrp_initialize (void)
>>>>    vr_phi_edge_counts = XCNEWVEC (int, num_ssa_names);
>>>>    bitmap_obstack_initialize (&vrp_equiv_obstack);
>>>>
>>>> +  if (dom_p)
>>>> +    return;
>>>> +
>>>>
>>>> split the function instead.
>>>>
>>>> @@ -7926,7 +7992,8 @@ vrp_visit_switch_stmt (gswitch *stmt, edge
>>>> *taken_edge_p)
>>>>     If STMT produces a varying value, return SSA_PROP_VARYING.  */
>>>>
>>>>  static enum ssa_prop_result
>>>> -vrp_visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
>>>> +vrp_visit_stmt_worker (gimple *stmt, bool dom_p,  edge *taken_edge_p,
>>>> +                      tree *output_p)
>>>>  {
>>>>    tree def;
>>>>    ssa_op_iter iter;
>>>> @@ -7940,7 +8007,7 @@ vrp_visit_stmt (gimple *stmt, edge
>>>> *taken_edge_p, tree *output_p)
>>>>    if (!stmt_interesting_for_vrp (stmt))
>>>>      gcc_assert (stmt_ends_bb_p (stmt));
>>>>    else if (is_gimple_assign (stmt) || is_gimple_call (stmt))
>>>> -    return vrp_visit_assignment_or_call (stmt, output_p);
>>>> +    return vrp_visit_assignment_or_call (stmt, dom_p, output_p);
>>>>    else if (gimple_code (stmt) == GIMPLE_COND)
>>>>      return vrp_visit_cond_stmt (as_a <gcond *> (stmt), taken_edge_p);
>>>>    else if (gimple_code (stmt) == GIMPLE_SWITCH)
>>>> @@ -7954,6 +8021,12 @@ vrp_visit_stmt (gimple *stmt, edge
>>>> *taken_edge_p, tree *output_p)
>>>>    return SSA_PROP_VARYING;
>>>>  }
>>>>
>>>> +static enum ssa_prop_result
>>>> +vrp_visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
>>>> +{
>>>> +  return vrp_visit_stmt_worker (stmt, false, taken_edge_p, output_p);
>>>> +}
>>>>
>>>> as said the refactoring that would be appreciated is to split out the
>>>> update_value_range calls
>>>> from the worker functions so you can call the respective functions
>>>> from the DOM implementations.
>>>> That they are globbed in vrp_visit_stmt currently is due to the API of
>>>> the SSA propagator.
>>>
>>> Sent this as separate patch for easy reviewing and testing.
>>
>> Thanks.
>>
>>>>
>>>> @@ -8768,6 +8842,12 @@ vrp_visit_phi_node (gphi *phi)
>>>>               fprintf (dump_file, "\n");
>>>>             }
>>>>
>>>> +         if (dom_p && vr_arg.type == VR_UNDEFINED)
>>>> +           {
>>>> +             set_value_range_to_varying (&vr_result);
>>>> +             break;
>>>> +           }
>>>> +
>>>>
>>>> eh...  ok, so another way to attack this is, instead of initializing
>>>> the lattice to sth else
>>>> than VR_UNDEFINED, make sure to drop the lattice to varying for all PHI
>>>> args on
>>>> yet unvisited incoming edges (you're not doing optimistic VRP).  That's
>>>> the only
>>>> place you _have_ to do it.
>>>
>>>
>>> Even when it is initialize (as I am doing now), we can still end up with
>>> VR_UNDEFINED during the propagation.  I have just left the above so that we
>>> dont end up with the wrong VR.
>>
>> How would we end up with wrong VRs?  I see
>>
>> +         /* 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);
>>
>> where you already disregard UNDEFINED as old_vr.
>>
>> What you might be missing is to set all DEFs on !stmt_interesting_for_vrp to
>> VARYING.  Also
>>
>> +      if (stmt_interesting_for_vrp (stmt))
>> +       {
>> +         tree lhs = gimple_get_lhs (stmt);
>> +         value_range vr = VR_INITIALIZER;
>> +         vrp_visit_stmt_worker (stmt, &taken_edge, &output, &vr);
>> +         update_value_range (lhs, &vr);
>> +
>> +         /* Try folding stmts with the VR discovered.  */
>> +         if (fold_stmt (&gsi, follow_single_use_edges))
>> +           update_stmt (gsi_stmt (gsi));
>>
>> folding here can introduce additional stmts and thus unvisited SSA defs
>> which would end up with VR_UNINITIALIZED defs - I don't see exactly
>> where that would cause issues but I'm not sure it might not.  So better
>> use fold_stmt_inplace or alternatively if fold_stmt returned true then,
>> remembering the previous stmt gsi, iterate over all stmts emitted and
>> set their defs to varying (or re-visit them).  See for example how
>> tree-ssa-forwprop.c does this re-visiting (it revisits all changed stmts).
>
> I am now setting the results of stmts that are not interesting to vrp
> to VR_VARYING.
>
> Also, before visiting PHI, if any of the arguments are undefined,
> result of the PHI is also set varying.
>
> I have removed all the others. This now bootstraps and passes
> regressions (see attached patch).
>
>
>> 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.
>
> 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?
>
> 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
Richard Biener Sept. 14, 2016, 12:04 p.m. UTC | #2
On Tue, Aug 23, 2016 at 4:11 AM, Kugan Vivekanandarajah
<kugan.vivekanandarajah@linaro.org> wrote:
> Hi,
>
> On 19 August 2016 at 21:41, Richard Biener <richard.guenther@gmail.com> wrote:
>> On Tue, Aug 16, 2016 at 9:45 AM, kugan
>> <kugan.vivekanandarajah@linaro.org> wrote:
>>> Hi Richard,
>>>
>>> On 12/08/16 20:43, Richard Biener wrote:
>>>>
>>>> On Wed, Aug 3, 2016 at 3:17 AM, kugan <kugan.vivekanandarajah@linaro.org>
>>>> wrote:
>>>
>>>
>>> [SNIP]
>>>
>>>>
>>>> diff --git a/gcc/common.opt b/gcc/common.opt
>>>> index 8a292ed..7028cd4 100644
>>>> --- a/gcc/common.opt
>>>> +++ b/gcc/common.opt
>>>> @@ -2482,6 +2482,10 @@ ftree-vrp
>>>>  Common Report Var(flag_tree_vrp) Init(0) Optimization
>>>>  Perform Value Range Propagation on trees.
>>>>
>>>> +fdisable-tree-evrp
>>>> +Common Report Var(flag_disable_early_vrp) Init(0) Optimization
>>>> +Disable Early Value Range Propagation on trees.
>>>> +
>>>>
>>>> no please, this is automatically supported via -fdisable-
>>>
>>>
>>> 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.

>>>>
>>>> @@ -1728,11 +1736,12 @@ extract_range_from_assert (value_range *vr_p, tree
>>>> expr)
>>>>      always false.  */
>>>>
>>>>  static void
>>>> -extract_range_from_ssa_name (value_range *vr, tree var)
>>>> +extract_range_from_ssa_name (value_range *vr, bool dom_p, tree var)
>>>>  {
>>>>    value_range *var_vr = get_value_range (var);
>>>>
>>>> -  if (var_vr->type != VR_VARYING)
>>>> +  if (var_vr->type != VR_VARYING
>>>> +      && (!dom_p || var_vr->type != VR_UNDEFINED))
>>>>      copy_value_range (vr, var_vr);
>>>>    else
>>>>      set_value_range (vr, VR_RANGE, var, var, NULL);
>>>>
>>>> why do you need these changes?  I think I already told you you need to
>>>> initialize the lattice to sth else than VR_UNDEFINED and that you can't
>>>> fully re-use update_value_range.  If you don't want to do that then
>>>> instead
>>>> of doing changes all over the place do it in get_value_range and have a
>>>> global flag.
>>>
>>>
>>> I have now added a global early_vrp_p and use this to initialize
>>> VR_INITIALIZER and get_value_range default to VR_VARYING.
>>
>> ICK.  Ok, I see that this works, but it is quite ugly, so (see below)
>>
>>>>
>>>>
>>>> @@ -3594,7 +3643,8 @@ extract_range_from_cond_expr (value_range *vr,
>>>> gassign *stmt)
>>>>     on the range of its operand and the expression code.  */
>>>>
>>>>  static void
>>>> -extract_range_from_comparison (value_range *vr, enum tree_code code,
>>>> +extract_range_from_comparison (value_range *vr,
>>>> +                              enum tree_code code,
>>>>                                tree type, tree op0, tree op1)
>>>>  {
>>>>    bool sop = false;
>>>>
>>>> remove these kind of no-op changes.
>>>
>>>
>>> Done.
>>>
>>>
>>>>
>>>> +/* 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 (void)
>>>> +vrp_initialize (bool dom_p)
>>>>  {
>>>>    basic_block bb;
>>>>
>>>> @@ -6949,6 +7010,9 @@ vrp_initialize (void)
>>>>    vr_phi_edge_counts = XCNEWVEC (int, num_ssa_names);
>>>>    bitmap_obstack_initialize (&vrp_equiv_obstack);
>>>>
>>>> +  if (dom_p)
>>>> +    return;
>>>> +
>>>>
>>>> split the function instead.
>>>>
>>>> @@ -7926,7 +7992,8 @@ vrp_visit_switch_stmt (gswitch *stmt, edge
>>>> *taken_edge_p)
>>>>     If STMT produces a varying value, return SSA_PROP_VARYING.  */
>>>>
>>>>  static enum ssa_prop_result
>>>> -vrp_visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
>>>> +vrp_visit_stmt_worker (gimple *stmt, bool dom_p,  edge *taken_edge_p,
>>>> +                      tree *output_p)
>>>>  {
>>>>    tree def;
>>>>    ssa_op_iter iter;
>>>> @@ -7940,7 +8007,7 @@ vrp_visit_stmt (gimple *stmt, edge
>>>> *taken_edge_p, tree *output_p)
>>>>    if (!stmt_interesting_for_vrp (stmt))
>>>>      gcc_assert (stmt_ends_bb_p (stmt));
>>>>    else if (is_gimple_assign (stmt) || is_gimple_call (stmt))
>>>> -    return vrp_visit_assignment_or_call (stmt, output_p);
>>>> +    return vrp_visit_assignment_or_call (stmt, dom_p, output_p);
>>>>    else if (gimple_code (stmt) == GIMPLE_COND)
>>>>      return vrp_visit_cond_stmt (as_a <gcond *> (stmt), taken_edge_p);
>>>>    else if (gimple_code (stmt) == GIMPLE_SWITCH)
>>>> @@ -7954,6 +8021,12 @@ vrp_visit_stmt (gimple *stmt, edge
>>>> *taken_edge_p, tree *output_p)
>>>>    return SSA_PROP_VARYING;
>>>>  }
>>>>
>>>> +static enum ssa_prop_result
>>>> +vrp_visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
>>>> +{
>>>> +  return vrp_visit_stmt_worker (stmt, false, taken_edge_p, output_p);
>>>> +}
>>>>
>>>> as said the refactoring that would be appreciated is to split out the
>>>> update_value_range calls
>>>> from the worker functions so you can call the respective functions
>>>> from the DOM implementations.
>>>> That they are globbed in vrp_visit_stmt currently is due to the API of
>>>> the SSA propagator.
>>>
>>> Sent this as separate patch for easy reviewing and testing.
>>
>> Thanks.
>>
>>>>
>>>> @@ -8768,6 +8842,12 @@ vrp_visit_phi_node (gphi *phi)
>>>>               fprintf (dump_file, "\n");
>>>>             }
>>>>
>>>> +         if (dom_p && vr_arg.type == VR_UNDEFINED)
>>>> +           {
>>>> +             set_value_range_to_varying (&vr_result);
>>>> +             break;
>>>> +           }
>>>> +
>>>>
>>>> eh...  ok, so another way to attack this is, instead of initializing
>>>> the lattice to sth else
>>>> than VR_UNDEFINED, make sure to drop the lattice to varying for all PHI
>>>> args on
>>>> yet unvisited incoming edges (you're not doing optimistic VRP).  That's
>>>> the only
>>>> place you _have_ to do it.
>>>
>>>
>>> Even when it is initialize (as I am doing now), we can still end up with
>>> VR_UNDEFINED during the propagation.  I have just left the above so that we
>>> dont end up with the wrong VR.
>>
>> How would we end up with wrong VRs?  I see
>>
>> +         /* 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);
>>
>> where you already disregard UNDEFINED as old_vr.
>>
>> What you might be missing is to set all DEFs on !stmt_interesting_for_vrp to
>> VARYING.  Also
>>
>> +      if (stmt_interesting_for_vrp (stmt))
>> +       {
>> +         tree lhs = gimple_get_lhs (stmt);
>> +         value_range vr = VR_INITIALIZER;
>> +         vrp_visit_stmt_worker (stmt, &taken_edge, &output, &vr);
>> +         update_value_range (lhs, &vr);
>> +
>> +         /* Try folding stmts with the VR discovered.  */
>> +         if (fold_stmt (&gsi, follow_single_use_edges))
>> +           update_stmt (gsi_stmt (gsi));
>>
>> folding here can introduce additional stmts and thus unvisited SSA defs
>> which would end up with VR_UNINITIALIZED defs - I don't see exactly
>> where that would cause issues but I'm not sure it might not.  So better
>> use fold_stmt_inplace or alternatively if fold_stmt returned true then,
>> remembering the previous stmt gsi, iterate over all stmts emitted and
>> set their defs to varying (or re-visit them).  See for example how
>> tree-ssa-forwprop.c does this re-visiting (it revisits all changed stmts).
>
> I am now setting the results of stmts that are not interesting to vrp
> to VR_VARYING.
>
> Also, before visiting PHI, if any of the arguments are undefined,
> result of the PHI is also set varying.
>
> I have removed all the others. This now bootstraps and passes
> regressions (see attached patch).
>
>
>> 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.

> 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.


 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.

+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;
         }

+  /* 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))
+       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.

+         /* 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.

+         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.

+                  || 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).

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
Jan Hubicka Sept. 14, 2016, 9:36 p.m. UTC | #3
> +  /* 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))
> +       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.
How IRA bugs affects early passes?

Honza
Richard Biener Sept. 15, 2016, 5:55 a.m. UTC | #4
On September 14, 2016 11:36:16 PM GMT+02:00, Jan Hubicka <hubicka@ucw.cz> wrote:
>> +  /* 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))
>> +       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.
>How IRA bugs affects early passes?

IRA bogously relies on BB_VISITED being cleared at pass start.

Richard.

>Honza
Jeff Law Sept. 15, 2016, 2:45 p.m. UTC | #5
On 09/14/2016 11:55 PM, Richard Biener wrote:
> On September 14, 2016 11:36:16 PM GMT+02:00, Jan Hubicka <hubicka@ucw.cz> wrote:
>>> +  /* 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))
>>> +       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.
>> How IRA bugs affects early passes?
>
> IRA bogously relies on BB_VISITED being cleared at pass start.
Seems like IRA ought to be fixed to clear BB_VISITED on every block as 
part of its initialization.

Jeff
Richard Biener Sept. 16, 2016, 8:50 a.m. UTC | #6
On Thu, Sep 15, 2016 at 4:45 PM, Jeff Law <law@redhat.com> wrote:
> On 09/14/2016 11:55 PM, Richard Biener wrote:
>>
>> On September 14, 2016 11:36:16 PM GMT+02:00, Jan Hubicka <hubicka@ucw.cz>
>> wrote:
>>>>
>>>> +  /* 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))
>>>> +       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.
>>>
>>> How IRA bugs affects early passes?
>>
>>
>> IRA bogously relies on BB_VISITED being cleared at pass start.
>
> Seems like IRA ought to be fixed to clear BB_VISITED on every block as part
> of its initialization.

Agreed but I didn't find the time to track down an appropriate place to do that.

Richard.

> Jeff
>
diff mbox

Patch

diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 1f04501..e00688a5 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -12433,6 +12433,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 <new>
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c
index e69de29..8c6e4e6 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c
+++ 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
index e69de29..e6d4235 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/evrp2.c
+++ 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
index e69de29..1a3bbd5 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/evrp3.c
+++ 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..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/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/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" } } */
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 86f2a8f..e4d789b 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -60,6 +60,7 @@  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"
 
 #define VR_INITIALIZER { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }
 
@@ -1455,44 +1456,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 +1512,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 +1704,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
@@ -6952,19 +6961,28 @@  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);
+}
+
+/* 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 ()
+{
+  basic_block bb;
 
   FOR_EACH_BB_FN (bb, cfun)
     {
@@ -8698,7 +8716,8 @@  vrp_meet (value_range *vr0, const value_range *vr1)
    value ranges, set a new range in VR_RESULT.  */
 
 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)
 {
   size_t i;
   tree lhs = PHI_RESULT (phi);
@@ -8821,6 +8840,7 @@  extract_range_from_phi_node (gphi *phi, value_range *vr_result)
      use the updated range and iterate one more time.  If we will not
      simulate this PHI again via the backedge allow us to iterate.  */
   if (edges > 0
+      && !early_vrp_p
       && gimple_phi_num_args (phi) > 1
       && edges == old_edges
       && lhs_vr->type != VR_UNDEFINED
@@ -8888,7 +8908,8 @@  scev_check:
      scev_check can be reached from two paths, one is a fall through from above
      "varying" label, the other is direct goto from code block which tries to
      avoid infinite simulation.  */
-  if ((l = loop_containing_stmt (phi))
+  if (!early_vrp_p
+      && (l = loop_containing_stmt (phi))
       && l->header == gimple_bb (phi))
     adjust_range_with_scev (vr_result, l, phi, lhs);
 
@@ -8918,7 +8939,7 @@  vrp_visit_phi_node (gphi *phi)
 {
   tree lhs = PHI_RESULT (phi);
   value_range vr_result = VR_INITIALIZER;
-  extract_range_from_phi_node (phi, &vr_result);
+  extract_range_from_phi_node (phi, &vr_result, false);
   if (update_value_range (lhs, &vr_result))
     {
       if (dump_file && (dump_flags & TDF_DETAILS))
@@ -10505,6 +10526,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.  */
 
@@ -10551,17 +10588,271 @@  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 ();
+/* Check to see if the PHI stmt has any back edges taht is not visited yet
+   (Circular dependancy).  In dominator based VRP, if we have back-edges,
+   we will have SSA_NAME operands with VR_UNDEFINED value range. */
 
-  /* So that we can distinguish between VRP data being available
-     and not available.  */
-  vr_value = NULL;
-  vr_phi_edge_counts = NULL;
+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;
+	}
+    }
+  return true;
+}
+
+/* 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.  */
+
+class evrp_dom_walker : public dom_walker
+{
+public:
+  evrp_dom_walker ()
+    : dom_walker (CDI_DOMINATORS), stack (10) {}
+  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<std::pair <const_tree, value_range*> > stack;
+};
+
+/* Return the singleton value-range for NAME or NAME.  */
+
+static inline tree
+evrp_valueize (tree name)
+{
+  if (TREE_CODE (name) == SSA_NAME)
+    {
+      value_range *vr = get_value_range (name);
+      if (vr->type == VR_RANGE
+	  && (range_int_cst_p (vr)
+	      || (TREE_CODE (vr->min) == SSA_NAME))
+	  && vrp_operand_equal_p (vr->min, vr->max))
+	return vr->min;
+    }
+  return name;
+}
+
+/* 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;
+  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 (stmt_interesting_for_vrp (phi)
+	  && stmt_visit_phi_node_in_dom_p (phi))
+	extract_range_from_phi_node (phi, &vr_result, true);
+      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;
+      /* 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)
+	    update_value_range (output, &vr);
+
+	  /* 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));
+
+	  if (did_replace
+	      && 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);
+	      unsigned ver = SSA_NAME_VERSION (def);
+	      if ((vr_value[ver]->type == VR_RANGE
+		   || 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);
+	    }
+	}
+      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));
+	}
+    }
+  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;
+
+  calculate_dominance_info (CDI_DOMINATORS);
+  FOR_EACH_BB_FN (bb, cfun)
+    {
+      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 (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 ();
+  return 0;
 }
 
 
@@ -10632,9 +10923,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);
 
@@ -10732,3 +11025,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);
+}
+