diff mbox series

[COMMITTED] PR tree-optimization/117398 - Don't call invert on VARYING.

Message ID 26efeb4d-94df-4cd6-9b8e-318d06136b5e@redhat.com
State New
Headers show
Series [COMMITTED] PR tree-optimization/117398 - Don't call invert on VARYING. | expand

Commit Message

Andrew MacLeod Nov. 4, 2024, 3 p.m. UTC
The invert() range operation is not supported on values of either 
VARYING or UNDEFINED.  Primarily this is because UNDEFINED has no type, 
which makes it impossible to perform invert() twice on a value, and 
produce that same value.  There were also times when it wasn't precisely 
clear what the client expects when UNDEFINED or VARYING is inverted.. so 
it is handled at the caller point.

When processing switches, whenever we find the ranges for a particular 
label, we invert that range, and intersect that inversion with the 
current "default:" ranges to determine the default case.   In this 
testcase, one label has all possible values, so the label was producing 
VARYING.  inverting that value was causing a trap.

This patch simple checks for VARYING and sets the default ranges to 
UNDEFINED in this case.

Bootstraps on x86_64-pc-linux-gnu with no regressions.  Pushed.

Backports to GCC12 - 14 forthcoming.

Andrew

Comments

Richard Biener Nov. 4, 2024, 3:27 p.m. UTC | #1
> Am 04.11.2024 um 16:01 schrieb Andrew MacLeod <amacleod@redhat.com>:
> 
> The invert() range operation is not supported on values of either VARYING or UNDEFINED.  Primarily this is because UNDEFINED has no type, which makes it impossible to perform invert() twice on a value, and produce that same value.  There were also times when it wasn't precisely clear what the client expects when UNDEFINED or VARYING is inverted.. so it is handled at the caller point.
> 
> When processing switches, whenever we find the ranges for a particular label, we invert that range, and intersect that inversion with the current "default:" ranges to determine the default case.   In this testcase, one label has all possible values, so the label was producing VARYING.  inverting that value was causing a trap.
> 
> This patch simple checks for VARYING and sets the default ranges to UNDEFINED in this case.

Is that correct?  The VARYING is not necessarily precise so „the rest“ should be VARYING as well?  That said, I don’t think you can use invert and intersect to compute the default case range.

Richard 

> Bootstraps on x86_64-pc-linux-gnu with no regressions.  Pushed.
> 
> Backports to GCC12 - 14 forthcoming.
> 
> Andrew
> 
> 
> <0001-Don-t-call-invert-on-VARYING.patch>
Andrew MacLeod Nov. 4, 2024, 3:32 p.m. UTC | #2
On 11/4/24 10:27, Richard Biener wrote:
>
>> Am 04.11.2024 um 16:01 schrieb Andrew MacLeod <amacleod@redhat.com>:
>>
>> The invert() range operation is not supported on values of either VARYING or UNDEFINED.  Primarily this is because UNDEFINED has no type, which makes it impossible to perform invert() twice on a value, and produce that same value.  There were also times when it wasn't precisely clear what the client expects when UNDEFINED or VARYING is inverted.. so it is handled at the caller point.
>>
>> When processing switches, whenever we find the ranges for a particular label, we invert that range, and intersect that inversion with the current "default:" ranges to determine the default case.   In this testcase, one label has all possible values, so the label was producing VARYING.  inverting that value was causing a trap.
>>
>> This patch simple checks for VARYING and sets the default ranges to UNDEFINED in this case.
> Is that correct?  The VARYING is not necessarily precise so „the rest“ should be VARYING as well?  That said, I don’t think you can use invert and intersect to compute the default case range.

The varying *is* precise. It only comes up with varying if all the 
precise values on each edge unioned together  come out to varying.   in 
this case, boolean true and false. proiduces varying, leaving nothing 
for the default cause.

Andrew
Richard Biener Nov. 4, 2024, 3:38 p.m. UTC | #3
> Am 04.11.2024 um 16:32 schrieb Andrew MacLeod <amacleod@redhat.com>:
> 
> 
>> On 11/4/24 10:27, Richard Biener wrote:
>> 
>>>> Am 04.11.2024 um 16:01 schrieb Andrew MacLeod <amacleod@redhat.com>:
>>> 
>>> The invert() range operation is not supported on values of either VARYING or UNDEFINED.  Primarily this is because UNDEFINED has no type, which makes it impossible to perform invert() twice on a value, and produce that same value.  There were also times when it wasn't precisely clear what the client expects when UNDEFINED or VARYING is inverted.. so it is handled at the caller point.
>>> 
>>> When processing switches, whenever we find the ranges for a particular label, we invert that range, and intersect that inversion with the current "default:" ranges to determine the default case.   In this testcase, one label has all possible values, so the label was producing VARYING.  inverting that value was causing a trap.
>>> 
>>> This patch simple checks for VARYING and sets the default ranges to UNDEFINED in this case.
>> Is that correct?  The VARYING is not necessarily precise so „the rest“ should be VARYING as well?  That said, I don’t think you can use invert and intersect to compute the default case range.
> 
> The varying *is* precise. It only comes up with varying if all the precise values on each edge unioned together  come out to varying.   in this case, boolean true and false. proiduces varying, leaving nothing for the default cause.

It never gets VARYING because too many incoming edges and thus conservatively merging subranges?  I would doubt ranger can do precise ranges this way.  1 and 5 are conservatively [1, 5] but the inversion does not include 2 and thus is not conservative.

Richard 



> 
> Andrew
>
Andrew MacLeod Nov. 4, 2024, 3:52 p.m. UTC | #4
>
>> Am 04.11.2024 um 16:32 schrieb Andrew MacLeod <amacleod@redhat.com>:
>>
>> 
>>> On 11/4/24 10:27, Richard Biener wrote:
>>>
>>>>> Am 04.11.2024 um 16:01 schrieb Andrew MacLeod <amacleod@redhat.com>:
>>>> The invert() range operation is not supported on values of either VARYING or UNDEFINED.  Primarily this is because UNDEFINED has no type, which makes it impossible to perform invert() twice on a value, and produce that same value.  There were also times when it wasn't precisely clear what the client expects when UNDEFINED or VARYING is inverted.. so it is handled at the caller point.
>>>>
>>>> When processing switches, whenever we find the ranges for a particular label, we invert that range, and intersect that inversion with the current "default:" ranges to determine the default case.   In this testcase, one label has all possible values, so the label was producing VARYING.  inverting that value was causing a trap.
>>>>
>>>> This patch simple checks for VARYING and sets the default ranges to UNDEFINED in this case.
>>> Is that correct?  The VARYING is not necessarily precise so „the rest“ should be VARYING as well?  That said, I don’t think you can use invert and intersect to compute the default case range.
>> The varying *is* precise. It only comes up with varying if all the precise values on each edge unioned together  come out to varying.   in this case, boolean true and false. proiduces varying, leaving nothing for the default cause.
> It never gets VARYING because too many incoming edges and thus conservatively merging subranges?  I would doubt ranger can do precise ranges this way.  1 and 5 are conservatively [1, 5] but the inversion does not include 2 and thus is not conservative.
>
> Richard
>
No, that does not happen,at least it should not.  If we have too many 
edges to process (-param=vrp-switch-limit=) , we do not process the 
switch at all.  The limit is because processing massive numbers of 
subranges can get expensive and ceases to be worthwhile after a while .

we've generated the range for default this way since gcc12 at least.  
Default starts with VARYING, and as we process each edge, we add the 
ranges on the edge to the destination case, and remove those ranges from 
the default case  (hence invert and intersect).   At the end, the range 
for default contains all the ranges that do not reach a case label.

Andrew
Andrew MacLeod Nov. 4, 2024, 11:28 p.m. UTC | #5
On 11/4/24 10:00, Andrew MacLeod wrote:
> The invert() range operation is not supported on values of either 
> VARYING or UNDEFINED.  Primarily this is because UNDEFINED has no 
> type, which makes it impossible to perform invert() twice on a value, 
> and produce that same value.  There were also times when it wasn't 
> precisely clear what the client expects when UNDEFINED or VARYING is 
> inverted.. so it is handled at the caller point.
>
> When processing switches, whenever we find the ranges for a particular 
> label, we invert that range, and intersect that inversion with the 
> current "default:" ranges to determine the default case.   In this 
> testcase, one label has all possible values, so the label was 
> producing VARYING.  inverting that value was causing a trap.
>
> This patch simple checks for VARYING and sets the default ranges to 
> UNDEFINED in this case.
>
> Bootstraps on x86_64-pc-linux-gnu with no regressions.  Pushed.
>
> Backports to GCC12 - 14 forthcoming.
>
> Andrew
>
>
Commited virtuslly identical patch:

commit e1154e294b3d8f7267612afb2113b2572cb39e33 (HEAD -> gcc14, 
origin/releases/gcc-14)
Author: Andrew MacLeod <amacleod@redhat.com>
Date:   Sat Nov 2 10:26:24 2024 -0400

     Don't call invert on VARYING.

     When all cases go to one label and resul in a VARYING value, we can't
     invert that value to remove all values from the default case. Simply
     check for this case and set the default to UNDEFINED.

             PR tree-optimization/117398
             gcc/
             * gimple-range-edge.cc 
(gimple_outgoing_range::calc_switch_ranges):
             Check for VARYING and don't call invert () on it.

             gcc/testsuite/
             * gcc.dg/pr117398.c: New.


commit 84b713589646c63b38ec55352fb87c1e80b69b66 (HEAD -> gcc-13)
Author: Andrew MacLeod <amacleod@redhat.com>
Date:   Mon Nov 4 10:02:35 2024 -0500

     Don't call invert on VARYING.

     When all cases go to one label and resul in a VARYING value, we can't
     invert that value to remove all values from the default case. Simply
     check for this case and set the default to UNDEFINED.

             PR tree-optimization/117398
             gcc/
             * gimple-range-edge.cc 
(gimple_outgoing_range::calc_switch_ranges):
             Check for VARYING and don't call invert () on it.

             gcc/testsuite/
             * gcc.dg/pr117398.c: New.

commit 4b9d6952d4024c5b8a66146ad497d63ad76a4095 (HEAD -> gcc12)
Author: Andrew MacLeod <amacleod@redhat.com>
Date:   Mon Nov 4 10:02:35 2024 -0500

     Don't call invert on VARYING.

     When all cases go to one label and resul in a VARYING value, we can't
     invert that value to remove all values from the default case. Simply
     check for this case and set the default to UNDEFINED.

             PR tree-optimization/117398
             gcc/
             * gimple-range-edge.cc 
(gimple_outgoing_range::calc_switch_ranges):
             Check for VARYING and don't call invert () on it.

             gcc/testsuite/
             * gcc.dg/pr117398.c: New.
diff mbox series

Patch

From 766075c47db5cc9d04463bfb2219b593bb4263ee Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacleod@redhat.com>
Date: Sat, 2 Nov 2024 10:26:24 -0400
Subject: [PATCH] Don't call invert on VARYING.

When all cases go to one label and resul in a VARYING value, we can't
invert that value to remove all values from the default case. Simply
check for this case and set the default to UNDEFINED.

	PR tree-optimization/117398
	gcc/
	* gimple-range-edge.cc (gimple_outgoing_range::calc_switch_ranges):
	Check for VARYING and don't call invert () on it.

	gcc/testsuite/
	* gcc.dg/pr117398.c: New.
---
 gcc/gimple-range-edge.cc        | 10 ++++++++--
 gcc/testsuite/gcc.dg/pr117398.c | 17 +++++++++++++++++
 2 files changed, 25 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr117398.c

diff --git a/gcc/gimple-range-edge.cc b/gcc/gimple-range-edge.cc
index e3a197a2293..d2387289ad2 100644
--- a/gcc/gimple-range-edge.cc
+++ b/gcc/gimple-range-edge.cc
@@ -159,8 +159,14 @@  gimple_outgoing_range::calc_switch_ranges (gswitch *sw)
       // Remove the case range from the default case.
       int_range_max def_range (type, low, high);
       range_cast (def_range, type);
-      def_range.invert ();
-      default_range.intersect (def_range);
+      // If all possible values are taken, set default_range to UNDEFINED.
+      if (def_range.varying_p ())
+	default_range.set_undefined ();
+      else
+	{
+	  def_range.invert ();
+	  default_range.intersect (def_range);
+	}
 
       // Create/union this case with anything on else on the edge.
       int_range_max case_range (type, low, high);
diff --git a/gcc/testsuite/gcc.dg/pr117398.c b/gcc/testsuite/gcc.dg/pr117398.c
new file mode 100644
index 00000000000..c43f2a3ed6b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr117398.c
@@ -0,0 +1,17 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+int a;
+void c(void);
+int d(_Bool b) {
+  switch (b+0) {
+  case 0:
+    break;
+  case 1:
+    break;
+  default:
+    c();
+  }
+  if (b)
+    return a;
+}
-- 
2.45.0