diff mbox

[PR,tree-optimization/69270] Exploit VRP information in DOM

Message ID 5697508C.6050006@redhat.com
State New
Headers show

Commit Message

Jeff Law Jan. 14, 2016, 7:38 a.m. UTC
As noted in the BZ, DOM does not exploit VRP information to create 
additional equivalences in the arms of conditionals.

This can cause DOM to miss relatively simple optimizations that show up 
in the adpcm benchmark as well as within GCC itself.

The fix is quite simple -- we just need to extend the code which used 
the implicit range of booleans to propagate on both sides of equality 
conditionals to use VRP information as well.

Once done we also need to make sure to convert the true/false value 
we're propagating to the right type.  Again, trivial.

The testcase is derived from the adpcm benchmark.  It checks that we 
optimize away the bit-xor on both arms of the conditional and that in 
turn allows other values to be discovered as constants.

Bootstrapped and regression tested on x86_64.  Installed on the trunk.



Jeff
commit e9d42e91d1e88ece5be38dbde81843e516b327e0
Author: Jeff Law <law@redhat.com>
Date:   Thu Jan 14 00:37:37 2016 -0700

    [PATCH][PR tree-optimization/69270] Exploit VRP information in DOM
    
    	PR tree-optimization/69270
    	* tree-ssa-dom.c (ssa_name_has_boolean_range): New function.
    	(record_edge_info): Use it.  Convert boolean_{true,false}_node
    	to the type of op0.
    
    	PR tree-optimization/69270
    	* gcc.dg/tree-ssa/pr69270.c: New test.

Comments

Jakub Jelinek Jan. 14, 2016, 7:46 a.m. UTC | #1
On Thu, Jan 14, 2016 at 12:38:52AM -0700, Jeff Law wrote:
> +  /* An integral type with more precision, but the object
> +     only takes on values [0..1] as determined by VRP
> +     analysis.  */
> +  wide_int min, max;
> +  if (INTEGRAL_TYPE_P (TREE_TYPE (op))
> +      && get_range_info (op, &min, &max) == VR_RANGE
> +      && wi::eq_p (min, 0)
> +      && wi::eq_p (max, 1))
> +    return true;

You could use and/or:
  if (INTEGRAL_TYPE_P (TREE_TYPE (op)) && wi::eq_p (get_nonzero_bits (op), 1))
set_range_info for VR_RANGE should usually update also the non-zero bits, but
set_nonzero_bits does not update the recorded range.

	Jakub
Jakub Jelinek Jan. 14, 2016, 7:49 a.m. UTC | #2
On Thu, Jan 14, 2016 at 08:46:43AM +0100, Jakub Jelinek wrote:
> On Thu, Jan 14, 2016 at 12:38:52AM -0700, Jeff Law wrote:
> > +  /* An integral type with more precision, but the object
> > +     only takes on values [0..1] as determined by VRP
> > +     analysis.  */
> > +  wide_int min, max;
> > +  if (INTEGRAL_TYPE_P (TREE_TYPE (op))
> > +      && get_range_info (op, &min, &max) == VR_RANGE
> > +      && wi::eq_p (min, 0)
> > +      && wi::eq_p (max, 1))
> > +    return true;
> 
> You could use and/or:
>   if (INTEGRAL_TYPE_P (TREE_TYPE (op)) && wi::eq_p (get_nonzero_bits (op), 1))
> set_range_info for VR_RANGE should usually update also the non-zero bits, but
> set_nonzero_bits does not update the recorded range.

Though, that would need to be limited to TYPE_PRECISION (TREE_TYPE (op)) > 1
or TYPE_UNSIGNED.

BTW,

+  /* An integral type with a single bit of precision.  */                                                                                         
+  if (INTEGRAL_TYPE_P (TREE_TYPE (op))                                                                                                            
+      && TYPE_PRECISION (TREE_TYPE (op)) == 1)                                                                                                    
+    return true;                                                                                                                                  

does not guarantee values 0, 1, it can mean either 0, 1 or -1, 0.  So, if
-1, 0 is unacceptable, you need to use TYPE_UNSIGNED (TREE_TYPE (op)) too.

	Jakub
Richard Biener Jan. 14, 2016, 9:47 a.m. UTC | #3
On Thu, Jan 14, 2016 at 8:38 AM, Jeff Law <law@redhat.com> wrote:
>
> As noted in the BZ, DOM does not exploit VRP information to create
> additional equivalences in the arms of conditionals.
>
> This can cause DOM to miss relatively simple optimizations that show up in
> the adpcm benchmark as well as within GCC itself.
>
> The fix is quite simple -- we just need to extend the code which used the
> implicit range of booleans to propagate on both sides of equality
> conditionals to use VRP information as well.
>
> Once done we also need to make sure to convert the true/false value we're
> propagating to the right type.  Again, trivial.
>
> The testcase is derived from the adpcm benchmark.  It checks that we
> optimize away the bit-xor on both arms of the conditional and that in turn
> allows other values to be discovered as constants.
>
> Bootstrapped and regression tested on x86_64.  Installed on the trunk.
>
>
>
> Jeff
>
> commit e9d42e91d1e88ece5be38dbde81843e516b327e0
> Author: Jeff Law <law@redhat.com>
> Date:   Thu Jan 14 00:37:37 2016 -0700
>
>     [PATCH][PR tree-optimization/69270] Exploit VRP information in DOM
>
>         PR tree-optimization/69270
>         * tree-ssa-dom.c (ssa_name_has_boolean_range): New function.
>         (record_edge_info): Use it.  Convert boolean_{true,false}_node
>         to the type of op0.
>
>         PR tree-optimization/69270
>         * gcc.dg/tree-ssa/pr69270.c: New test.
>
> diff --git a/gcc/ChangeLog b/gcc/ChangeLog
> index dc13621..40e3dfb 100644
> --- a/gcc/ChangeLog
> +++ b/gcc/ChangeLog
> @@ -1,3 +1,10 @@
> +2016-01-14  Jeff Law  <law@redhat.com>
> +
> +       PR tree-optimization/69270
> +       * tree-ssa-dom.c (ssa_name_has_boolean_range): New function.
> +       (record_edge_info): Use it.  Convert boolean_{true,false}_node
> +       to the type of op0.
> +
>  2016-01-13  Jan Hubicka  <hubicka@ucw.cz>
>
>         PR ipa/66487
> diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
> index f393e25..63976ea 100644
> --- a/gcc/testsuite/ChangeLog
> +++ b/gcc/testsuite/ChangeLog
> @@ -1,3 +1,8 @@
> +2016-01-14  Jeff Law  <law@redhat.com>
> +
> +       PR tree-optimization/69270
> +       * gcc.dg/tree-ssa/pr69270.c: New test.
> +
>  2016-01-13  Bernd Schmidt  <bschmidt@redhat.com>
>
>         PR c/66208
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr69270.c
> b/gcc/testsuite/gcc.dg/tree-ssa/pr69270.c
> new file mode 100644
> index 0000000..529b521
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr69270.c
> @@ -0,0 +1,42 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fsplit-paths -fdump-tree-dom3-details" } */
> +
> +/* There should be two references to bufferstep that turn into
> +   constants.  */
> +/* { dg-final { scan-tree-dump-times "Replaced .bufferstep_\[0-9\]+. with
> constant .0." 1 "dom3"} } */
> +/* { dg-final { scan-tree-dump-times "Replaced .bufferstep_\[0-9\]+. with
> constant .1." 1 "dom3"} } */
> +
> +/* And some assignments ought to fold down to constants.  */
> +/* { dg-final { scan-tree-dump-times "Folded to: _\[0-9\]+ = 1;" 2 "dom3"}
> } */
> +/* { dg-final { scan-tree-dump-times "Folded to: _\[0-9\]+ = 0;" 2 "dom3"}
> } */
> +
> +/* The XOR operations should have been optimized to constants.  */
> +/* { dg-final { scan-tree-dump-not "bit_xor" "dom3"} } */
> +
> +
> +extern int *stepsizeTable;
> +
> +void
> +adpcm_coder (signed char *outdata, int len)
> +{
> +  signed char *outp;
> +  int delta;
> +  int outputbuffer;
> +  int bufferstep = 0;
> +  outp = (signed char *) outdata;
> +  int step = 0;
> +  int index = 0;
> +  int diff = 0;
> +  for (; len > 0; len--)
> +    {
> +      delta = 0;
> +      if (diff >= step)
> +       delta = 4;
> +      step = stepsizeTable[index];
> +      if (bufferstep)
> +       outputbuffer = (delta << 4) & 0xf0;
> +      else
> +       *outp++ = (delta & 0x0f) | outputbuffer;
> +      bufferstep = !bufferstep;
> +    }
> +}
> diff --git a/gcc/tree-ssa-dom.c b/gcc/tree-ssa-dom.c
> index 9d2e189..a9abed9 100644
> --- a/gcc/tree-ssa-dom.c
> +++ b/gcc/tree-ssa-dom.c
> @@ -316,6 +316,38 @@ record_conditions (struct edge_info *edge_info, tree
> cond, tree inverted)
>    edge_info->cond_equivalences.safe_push (c);
>  }
>
> +/* Return TRUE is OP, an SSA_NAME has a range of values [0..1], false
> +   otherwise.
> +
> +   This can be because it is a boolean type, any type with
> +   a single bit of precision, or has known range of values
> +   it might old of [0..1] via VRP analysis.  */
> +
> +static bool
> +ssa_name_has_boolean_range (tree op)
> +{
> +  /* Boolean types always have a range [0..1].  */
> +  if (TREE_CODE (TREE_TYPE (op)) == BOOLEAN_TYPE)
> +    return true;
> +
> +  /* An integral type with a single bit of precision.  */
> +  if (INTEGRAL_TYPE_P (TREE_TYPE (op))
> +      && TYPE_PRECISION (TREE_TYPE (op)) == 1)
> +    return true;
> +
> +  /* An integral type with more precision, but the object
> +     only takes on values [0..1] as determined by VRP
> +     analysis.  */
> +  wide_int min, max;
> +  if (INTEGRAL_TYPE_P (TREE_TYPE (op))
> +      && get_range_info (op, &min, &max) == VR_RANGE
> +      && wi::eq_p (min, 0)
> +      && wi::eq_p (max, 1))
> +    return true;
> +
> +  return false;
> +}
> +
>  /* We have finished optimizing BB, record any information implied by
>     taking a specific outgoing edge from BB.  */
>
> @@ -390,36 +422,32 @@ record_edge_info (basic_block bb)
>               can record an equivalence for OP0 rather than COND.  */
>            if ((code == EQ_EXPR || code == NE_EXPR)
>                && TREE_CODE (op0) == SSA_NAME
> -              && TREE_CODE (TREE_TYPE (op0)) == BOOLEAN_TYPE
> +             && ssa_name_has_boolean_range (op0)
>                && is_gimple_min_invariant (op1))
>              {
> +             tree true_val = fold_convert (TREE_TYPE (op0),
> +                                           boolean_true_node);
> +             tree false_val = fold_convert (TREE_TYPE (op0),
> +                                            boolean_false_node);

Apart from what Jakub said we have constant_boolean_node for this,

  true_val = constant_boolean_node (true, TREE_TYPE (op0));
...

>                if (code == EQ_EXPR)
>                  {
>                    edge_info = allocate_edge_info (true_edge);
>                    edge_info->lhs = op0;
> -                  edge_info->rhs = (integer_zerop (op1)
> -                                    ? boolean_false_node
> -                                    : boolean_true_node);
> +                  edge_info->rhs = (integer_zerop (op1) ? false_val :
> true_val);
>
>                    edge_info = allocate_edge_info (false_edge);
>                    edge_info->lhs = op0;
> -                  edge_info->rhs = (integer_zerop (op1)
> -                                    ? boolean_true_node
> -                                    : boolean_false_node);
> +                  edge_info->rhs = (integer_zerop (op1) ? true_val :
> false_val);
>                  }
>                else
>                  {
>                    edge_info = allocate_edge_info (true_edge);
>                    edge_info->lhs = op0;
> -                  edge_info->rhs = (integer_zerop (op1)
> -                                    ? boolean_true_node
> -                                    : boolean_false_node);
> +                  edge_info->rhs = (integer_zerop (op1) ? true_val :
> false_val);
>
>                    edge_info = allocate_edge_info (false_edge);
>                    edge_info->lhs = op0;
> -                  edge_info->rhs = (integer_zerop (op1)
> -                                    ? boolean_false_node
> -                                    : boolean_true_node);
> +                  edge_info->rhs = (integer_zerop (op1) ? false_val :
> true_val);
>                  }
>              }
>            else if (is_gimple_min_invariant (op0)
>
Jeff Law Jan. 14, 2016, 6:14 p.m. UTC | #4
On 01/14/2016 12:49 AM, Jakub Jelinek wrote:
> On Thu, Jan 14, 2016 at 08:46:43AM +0100, Jakub Jelinek wrote:
>> On Thu, Jan 14, 2016 at 12:38:52AM -0700, Jeff Law wrote:
>>> +  /* An integral type with more precision, but the object
>>> +     only takes on values [0..1] as determined by VRP
>>> +     analysis.  */
>>> +  wide_int min, max;
>>> +  if (INTEGRAL_TYPE_P (TREE_TYPE (op))
>>> +      && get_range_info (op, &min, &max) == VR_RANGE
>>> +      && wi::eq_p (min, 0)
>>> +      && wi::eq_p (max, 1))
>>> +    return true;
>>
>> You could use and/or:
>>    if (INTEGRAL_TYPE_P (TREE_TYPE (op)) && wi::eq_p (get_nonzero_bits (op), 1))
>> set_range_info for VR_RANGE should usually update also the non-zero bits, but
>> set_nonzero_bits does not update the recorded range.
>
> Though, that would need to be limited to TYPE_PRECISION (TREE_TYPE (op)) > 1
> or TYPE_UNSIGNED.
Quite surprisingly, this does seem to do better fairly often.  Usually 
it's just getting more constants into the PHI nodes without further 
improvements.  However occasionally I see a PHI that turns into a 
constant, which is then propagated to a use where we're able to simplify 
some arithmetic/logical.

Unfortunately it doesn't make a bit of difference in the final output, 
so something post DOM was picking up these anyway (most likely VRP2). 
But I'm a fan of getting stuff optimized earlier in the pipeline when 
it's reasonable to do so, and this seems reasonable.

Limiting to TYPE_PRECISION > 1 or TYPE_UNSIGNED ought to be trivial.

>
> BTW,
>
> +  /* An integral type with a single bit of precision.  */
> +  if (INTEGRAL_TYPE_P (TREE_TYPE (op))
> +      && TYPE_PRECISION (TREE_TYPE (op)) == 1)
> +    return true;
>
> does not guarantee values 0, 1, it can mean either 0, 1 or -1, 0.  So, if
> -1, 0 is unacceptable, you need to use TYPE_UNSIGNED (TREE_TYPE (op)) too.
Hmm, then I think we've got other places that likely need updating.  I 
remember adding similar code elsewhere in the past couple years.  I'll 
have to do a little auditing.

jeff
Jeff Law Jan. 14, 2016, 6:27 p.m. UTC | #5
On 01/14/2016 02:47 AM, Richard Biener wrote:
> On Thu, Jan 14, 2016 at 8:38 AM, Jeff Law <law@redhat.com> wrote:
>>
>> As noted in the BZ, DOM does not exploit VRP information to create
>> additional equivalences in the arms of conditionals.
>>
>> This can cause DOM to miss relatively simple optimizations that show up in
>> the adpcm benchmark as well as within GCC itself.
>>
>> The fix is quite simple -- we just need to extend the code which used the
>> implicit range of booleans to propagate on both sides of equality
>> conditionals to use VRP information as well.
>>
>> Once done we also need to make sure to convert the true/false value we're
>> propagating to the right type.  Again, trivial.
>>
>> The testcase is derived from the adpcm benchmark.  It checks that we
>> optimize away the bit-xor on both arms of the conditional and that in turn
>> allows other values to be discovered as constants.
>>
>> Bootstrapped and regression tested on x86_64.  Installed on the trunk.
>>
>>
>>
>> Jeff
>>
>> commit e9d42e91d1e88ece5be38dbde81843e516b327e0
>> Author: Jeff Law <law@redhat.com>
>> Date:   Thu Jan 14 00:37:37 2016 -0700
>>
>>      [PATCH][PR tree-optimization/69270] Exploit VRP information in DOM
>>
>>          PR tree-optimization/69270
>>          * tree-ssa-dom.c (ssa_name_has_boolean_range): New function.
>>          (record_edge_info): Use it.  Convert boolean_{true,false}_node
>>          to the type of op0.
>>
>>          PR tree-optimization/69270
>>          * gcc.dg/tree-ssa/pr69270.c: New test.
>>
>> diff --git a/gcc/ChangeLog b/gcc/ChangeLog
>> index dc13621..40e3dfb 100644
>> --- a/gcc/ChangeLog
>> +++ b/gcc/ChangeLog
>> @@ -1,3 +1,10 @@
>> +2016-01-14  Jeff Law  <law@redhat.com>
>> +
>> +       PR tree-optimization/69270
>> +       * tree-ssa-dom.c (ssa_name_has_boolean_range): New function.
>> +       (record_edge_info): Use it.  Convert boolean_{true,false}_node
>> +       to the type of op0.
>> +
>>   2016-01-13  Jan Hubicka  <hubicka@ucw.cz>
>>
>>          PR ipa/66487
>> diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
>> index f393e25..63976ea 100644
>> --- a/gcc/testsuite/ChangeLog
>> +++ b/gcc/testsuite/ChangeLog
>> @@ -1,3 +1,8 @@
>> +2016-01-14  Jeff Law  <law@redhat.com>
>> +
>> +       PR tree-optimization/69270
>> +       * gcc.dg/tree-ssa/pr69270.c: New test.
>> +
>>   2016-01-13  Bernd Schmidt  <bschmidt@redhat.com>
>>
>>          PR c/66208
>> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr69270.c
>> b/gcc/testsuite/gcc.dg/tree-ssa/pr69270.c
>> new file mode 100644
>> index 0000000..529b521
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr69270.c
>> @@ -0,0 +1,42 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-O2 -fsplit-paths -fdump-tree-dom3-details" } */
>> +
>> +/* There should be two references to bufferstep that turn into
>> +   constants.  */
>> +/* { dg-final { scan-tree-dump-times "Replaced .bufferstep_\[0-9\]+. with
>> constant .0." 1 "dom3"} } */
>> +/* { dg-final { scan-tree-dump-times "Replaced .bufferstep_\[0-9\]+. with
>> constant .1." 1 "dom3"} } */
>> +
>> +/* And some assignments ought to fold down to constants.  */
>> +/* { dg-final { scan-tree-dump-times "Folded to: _\[0-9\]+ = 1;" 2 "dom3"}
>> } */
>> +/* { dg-final { scan-tree-dump-times "Folded to: _\[0-9\]+ = 0;" 2 "dom3"}
>> } */
>> +
>> +/* The XOR operations should have been optimized to constants.  */
>> +/* { dg-final { scan-tree-dump-not "bit_xor" "dom3"} } */
>> +
>> +
>> +extern int *stepsizeTable;
>> +
>> +void
>> +adpcm_coder (signed char *outdata, int len)
>> +{
>> +  signed char *outp;
>> +  int delta;
>> +  int outputbuffer;
>> +  int bufferstep = 0;
>> +  outp = (signed char *) outdata;
>> +  int step = 0;
>> +  int index = 0;
>> +  int diff = 0;
>> +  for (; len > 0; len--)
>> +    {
>> +      delta = 0;
>> +      if (diff >= step)
>> +       delta = 4;
>> +      step = stepsizeTable[index];
>> +      if (bufferstep)
>> +       outputbuffer = (delta << 4) & 0xf0;
>> +      else
>> +       *outp++ = (delta & 0x0f) | outputbuffer;
>> +      bufferstep = !bufferstep;
>> +    }
>> +}
>> diff --git a/gcc/tree-ssa-dom.c b/gcc/tree-ssa-dom.c
>> index 9d2e189..a9abed9 100644
>> --- a/gcc/tree-ssa-dom.c
>> +++ b/gcc/tree-ssa-dom.c
>> @@ -316,6 +316,38 @@ record_conditions (struct edge_info *edge_info, tree
>> cond, tree inverted)
>>     edge_info->cond_equivalences.safe_push (c);
>>   }
>>
>> +/* Return TRUE is OP, an SSA_NAME has a range of values [0..1], false
>> +   otherwise.
>> +
>> +   This can be because it is a boolean type, any type with
>> +   a single bit of precision, or has known range of values
>> +   it might old of [0..1] via VRP analysis.  */
>> +
>> +static bool
>> +ssa_name_has_boolean_range (tree op)
>> +{
>> +  /* Boolean types always have a range [0..1].  */
>> +  if (TREE_CODE (TREE_TYPE (op)) == BOOLEAN_TYPE)
>> +    return true;
>> +
>> +  /* An integral type with a single bit of precision.  */
>> +  if (INTEGRAL_TYPE_P (TREE_TYPE (op))
>> +      && TYPE_PRECISION (TREE_TYPE (op)) == 1)
>> +    return true;
>> +
>> +  /* An integral type with more precision, but the object
>> +     only takes on values [0..1] as determined by VRP
>> +     analysis.  */
>> +  wide_int min, max;
>> +  if (INTEGRAL_TYPE_P (TREE_TYPE (op))
>> +      && get_range_info (op, &min, &max) == VR_RANGE
>> +      && wi::eq_p (min, 0)
>> +      && wi::eq_p (max, 1))
>> +    return true;
>> +
>> +  return false;
>> +}
>> +
>>   /* We have finished optimizing BB, record any information implied by
>>      taking a specific outgoing edge from BB.  */
>>
>> @@ -390,36 +422,32 @@ record_edge_info (basic_block bb)
>>                can record an equivalence for OP0 rather than COND.  */
>>             if ((code == EQ_EXPR || code == NE_EXPR)
>>                 && TREE_CODE (op0) == SSA_NAME
>> -              && TREE_CODE (TREE_TYPE (op0)) == BOOLEAN_TYPE
>> +             && ssa_name_has_boolean_range (op0)
>>                 && is_gimple_min_invariant (op1))
>>               {
>> +             tree true_val = fold_convert (TREE_TYPE (op0),
>> +                                           boolean_true_node);
>> +             tree false_val = fold_convert (TREE_TYPE (op0),
>> +                                            boolean_false_node);
>
> Apart from what Jakub said we have constant_boolean_node for this,
>
>    true_val = constant_boolean_node (true, TREE_TYPE (op0));
Will update.  Thanks.

jeff
diff mbox

Patch

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index dc13621..40e3dfb 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,10 @@ 
+2016-01-14  Jeff Law  <law@redhat.com>
+
+	PR tree-optimization/69270
+	* tree-ssa-dom.c (ssa_name_has_boolean_range): New function.
+	(record_edge_info): Use it.  Convert boolean_{true,false}_node
+	to the type of op0.
+
 2016-01-13  Jan Hubicka  <hubicka@ucw.cz>
 
 	PR ipa/66487
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index f393e25..63976ea 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@ 
+2016-01-14  Jeff Law  <law@redhat.com>
+
+	PR tree-optimization/69270
+	* gcc.dg/tree-ssa/pr69270.c: New test.
+
 2016-01-13  Bernd Schmidt  <bschmidt@redhat.com>
 
 	PR c/66208
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr69270.c b/gcc/testsuite/gcc.dg/tree-ssa/pr69270.c
new file mode 100644
index 0000000..529b521
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr69270.c
@@ -0,0 +1,42 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -fsplit-paths -fdump-tree-dom3-details" } */
+
+/* There should be two references to bufferstep that turn into
+   constants.  */
+/* { dg-final { scan-tree-dump-times "Replaced .bufferstep_\[0-9\]+. with constant .0." 1 "dom3"} } */
+/* { dg-final { scan-tree-dump-times "Replaced .bufferstep_\[0-9\]+. with constant .1." 1 "dom3"} } */
+
+/* And some assignments ought to fold down to constants.  */
+/* { dg-final { scan-tree-dump-times "Folded to: _\[0-9\]+ = 1;" 2 "dom3"} } */
+/* { dg-final { scan-tree-dump-times "Folded to: _\[0-9\]+ = 0;" 2 "dom3"} } */
+
+/* The XOR operations should have been optimized to constants.  */
+/* { dg-final { scan-tree-dump-not "bit_xor" "dom3"} } */
+
+
+extern int *stepsizeTable;
+
+void
+adpcm_coder (signed char *outdata, int len)
+{
+  signed char *outp;
+  int delta;
+  int outputbuffer;
+  int bufferstep = 0;
+  outp = (signed char *) outdata;
+  int step = 0;
+  int index = 0;
+  int diff = 0;
+  for (; len > 0; len--)
+    {
+      delta = 0;
+      if (diff >= step)
+	delta = 4;
+      step = stepsizeTable[index];
+      if (bufferstep)
+	outputbuffer = (delta << 4) & 0xf0;
+      else
+	*outp++ = (delta & 0x0f) | outputbuffer;
+      bufferstep = !bufferstep;
+    }
+}
diff --git a/gcc/tree-ssa-dom.c b/gcc/tree-ssa-dom.c
index 9d2e189..a9abed9 100644
--- a/gcc/tree-ssa-dom.c
+++ b/gcc/tree-ssa-dom.c
@@ -316,6 +316,38 @@  record_conditions (struct edge_info *edge_info, tree cond, tree inverted)
   edge_info->cond_equivalences.safe_push (c);
 }
 
+/* Return TRUE is OP, an SSA_NAME has a range of values [0..1], false
+   otherwise.
+
+   This can be because it is a boolean type, any type with
+   a single bit of precision, or has known range of values
+   it might old of [0..1] via VRP analysis.  */
+
+static bool
+ssa_name_has_boolean_range (tree op)
+{
+  /* Boolean types always have a range [0..1].  */
+  if (TREE_CODE (TREE_TYPE (op)) == BOOLEAN_TYPE)
+    return true;
+
+  /* An integral type with a single bit of precision.  */
+  if (INTEGRAL_TYPE_P (TREE_TYPE (op))
+      && TYPE_PRECISION (TREE_TYPE (op)) == 1)
+    return true;
+
+  /* An integral type with more precision, but the object
+     only takes on values [0..1] as determined by VRP
+     analysis.  */
+  wide_int min, max;
+  if (INTEGRAL_TYPE_P (TREE_TYPE (op))
+      && get_range_info (op, &min, &max) == VR_RANGE
+      && wi::eq_p (min, 0)
+      && wi::eq_p (max, 1))
+    return true;
+
+  return false;
+}
+
 /* We have finished optimizing BB, record any information implied by
    taking a specific outgoing edge from BB.  */
 
@@ -390,36 +422,32 @@  record_edge_info (basic_block bb)
              can record an equivalence for OP0 rather than COND.  */
           if ((code == EQ_EXPR || code == NE_EXPR)
               && TREE_CODE (op0) == SSA_NAME
-              && TREE_CODE (TREE_TYPE (op0)) == BOOLEAN_TYPE
+	      && ssa_name_has_boolean_range (op0)
               && is_gimple_min_invariant (op1))
             {
+	      tree true_val = fold_convert (TREE_TYPE (op0),
+					    boolean_true_node);
+	      tree false_val = fold_convert (TREE_TYPE (op0),
+					     boolean_false_node);
               if (code == EQ_EXPR)
                 {
                   edge_info = allocate_edge_info (true_edge);
                   edge_info->lhs = op0;
-                  edge_info->rhs = (integer_zerop (op1)
-                                    ? boolean_false_node
-                                    : boolean_true_node);
+                  edge_info->rhs = (integer_zerop (op1) ? false_val : true_val);
 
                   edge_info = allocate_edge_info (false_edge);
                   edge_info->lhs = op0;
-                  edge_info->rhs = (integer_zerop (op1)
-                                    ? boolean_true_node
-                                    : boolean_false_node);
+                  edge_info->rhs = (integer_zerop (op1) ? true_val : false_val);
                 }
               else
                 {
                   edge_info = allocate_edge_info (true_edge);
                   edge_info->lhs = op0;
-                  edge_info->rhs = (integer_zerop (op1)
-                                    ? boolean_true_node
-                                    : boolean_false_node);
+                  edge_info->rhs = (integer_zerop (op1) ? true_val : false_val);
 
                   edge_info = allocate_edge_info (false_edge);
                   edge_info->lhs = op0;
-                  edge_info->rhs = (integer_zerop (op1)
-                                    ? boolean_false_node
-                                    : boolean_true_node);
+                  edge_info->rhs = (integer_zerop (op1) ? false_val : true_val);
                 }
             }
           else if (is_gimple_min_invariant (op0)