File 3137-Fix-incorrect-range-calculation-for-operator-rem.patch of Package erlang

From b0926ff88a1efa13b73d466a6c7cfcd747076b14 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= <bjorn@erlang.org>
Date: Thu, 31 Aug 2023 06:50:13 +0200
Subject: [PATCH] Fix incorrect range calculation for operator `rem`

acf3116e55f238 enhanced the range calculation for `rem`, but at the
same time introduced a bug. For example:

    2 rem X

If the range for `X` was unknown, the compiler would calculate the
range for the remainder as `{2,2}`, while the correct range is
`{0,2}`. This commit corrects the range calculation for the remainder
to ensure that zero is always included in the range.
---
 erts/emulator/test/small_SUITE.erl      | 38 +++++++++++++++++++++++++
 lib/compiler/src/beam_bounds.erl        |  7 +++--
 lib/compiler/test/beam_bounds_SUITE.erl | 18 ++++++++++--
 3 files changed, 59 insertions(+), 4 deletions(-)

diff --git a/erts/emulator/test/small_SUITE.erl b/erts/emulator/test/small_SUITE.erl
index aa732c1e24..21cbf6135c 100644
--- a/erts/emulator/test/small_SUITE.erl
+++ b/erts/emulator/test/small_SUITE.erl
@@ -860,6 +860,22 @@ gen_div_function({Name,{A,B}}) ->
            put(prevent_div_rem_fusion, Q),
            R = X rem Y,
            {Q, R};
+        '@Name@'(any0, fixed, Y) ->
+           X = _@A@,
+           Q = X div Y,
+           R = X rem Y,
+           {Q, R};
+        '@Name@'(any1, fixed, Y) ->
+           X = _@A@,
+           R = X rem Y,
+           Q = X div Y,
+           {Q, R};
+        '@Name@'(any2, fixed, Y) ->
+           X = _@A@,
+           Q = X div Y,
+           put(prevent_div_rem_fusion, Q),
+           R = X rem Y,
+           {Q, R};
         '@Name@'(X0, Y0, integer0) ->
            Q = X0 div Y0,
            R = X0 rem Y0,
@@ -945,6 +961,22 @@ gen_div_function({Name,{A,B}}) ->
            Q = X div Y,
            put(prevent_div_rem_fusion, Q),
            R = X rem Y,
+           {Q, R};
+        '@Name@'(fixed, Y, any0) ->
+           X = _@A@,
+           Q = X div Y,
+           R = X rem Y,
+           {Q, R};
+        '@Name@'(fixed, Y, any1) ->
+           X = _@A@,
+           R = X rem Y,
+           Q = X div Y,
+           {Q, R};
+        '@Name@'(fixed, Y, any2) ->
+           X = _@A@,
+           Q = X div Y,
+           put(prevent_div_rem_fusion, Q),
+           R = X rem Y,
            {Q, R}. ").
 
 
@@ -969,6 +1001,9 @@ test_division([{Name,{A,B}}|T], Mod) ->
         PosRes = F(any0, A, fixed),
         PosRes = F(any1, A, fixed),
         PosRes = F(any2, A, fixed),
+        PosRes = F(any0, fixed, B),
+        PosRes = F(any1, fixed, B),
+        PosRes = F(any2, fixed, B),
 
         PosRes = F(A, B, integer0),
         PosRes = F(A, fixed, integer1),
@@ -985,6 +1020,9 @@ test_division([{Name,{A,B}}|T], Mod) ->
         PosRes = F(A, fixed, any0),
         PosRes = F(A, fixed, any1),
         PosRes = F(A, fixed, any2),
+        PosRes = F(fixed, B, any0),
+        PosRes = F(fixed, B, any1),
+        PosRes = F(fixed, B, any2),
 
         NegRes = F(integer0, -A, B),
         NegRes = F(integer1, -A, fixed),
diff --git a/lib/compiler/src/beam_bounds.erl b/lib/compiler/src/beam_bounds.erl
index cfa6e4d378..5c1b42745f 100644
--- a/lib/compiler/src/beam_bounds.erl
+++ b/lib/compiler/src/beam_bounds.erl
@@ -327,8 +327,11 @@ rem_bounds({A,B}, _) ->
     %% The sign of the remainder is the same as the sign of the
     %% left-hand side operand; it does not depend on the sign of the
     %% right-hand side operand. Therefore, the range of the remainder
-    %% is the same as the range of the left-hand side operand.
-    {A,B};
+    %% is the range of the left-hand side operand extended to always
+    %% include zero.
+    Min = inf_min(0, A),
+    Max = inf_max(0, B),
+    normalize({Min,Max});
 rem_bounds(_, _) ->
     any.
 
diff --git a/lib/compiler/test/beam_bounds_SUITE.erl b/lib/compiler/test/beam_bounds_SUITE.erl
index bee79533b9..d5c27d0bdf 100644
--- a/lib/compiler/test/beam_bounds_SUITE.erl
+++ b/lib/compiler/test/beam_bounds_SUITE.erl
@@ -133,6 +133,9 @@ division_bounds(_Config) ->
     {-50,50} = beam_bounds:bounds('div', {-50,-15}, {-10,'+inf'}),
     {-20,20} = beam_bounds:bounds('div', {-20,10}, any),
     {-7,7} = beam_bounds:bounds('div', {-5,7}, {'-inf',-1}),
+    {-42,42} = beam_bounds:bounds('div', {42,42}, any),
+    {-42,42} = beam_bounds:bounds('div', {-42,-42}, any),
+
     any = beam_bounds:bounds('div', {'-inf',10}, any),
     any = beam_bounds:bounds('div', {0,'+inf'}, any),
 
@@ -153,15 +156,26 @@ rem_bounds(_Config) ->
 
     {-7,7} = beam_bounds:bounds('rem', {'-inf',10}, {1,8}),
     {0,7} = beam_bounds:bounds('rem', {10,'+inf'}, {1,8}),
+    {0,'+inf'} = beam_bounds:bounds('rem', {17,'+inf'}, any),
 
-    {1,10} = beam_bounds:bounds('rem', {1,10}, {'-inf',10}),
-    {20,'+inf'} = beam_bounds:bounds('rem', {20,'+inf'}, {10,'+inf'}),
+    {0,10} = beam_bounds:bounds('rem', {1,10}, {'-inf',10}),
+    {0,'+inf'} = beam_bounds:bounds('rem', {20,'+inf'}, {10,'+inf'}),
     {'-inf',10} = beam_bounds:bounds('rem', {'-inf',10}, any),
 
     {-11,10} = beam_bounds:bounds('rem', {-11,10}, {'-inf',89}),
     {-11,10} = beam_bounds:bounds('rem', {-11,10}, {7,'+inf'}),
     {-11,10} = beam_bounds:bounds('rem', {-11,10}, {'-inf',113}),
     {-11,10} = beam_bounds:bounds('rem', {-11,10}, {55,'+inf'}),
+    {-11,10} = beam_bounds:bounds('rem', {-11,10}, any),
+
+    {0,0} = beam_bounds:bounds('rem', {0,0}, any),
+    {0,1} = beam_bounds:bounds('rem', {1,1}, any),
+    {0,2} = beam_bounds:bounds('rem', {2,2}, any),
+    {0,3} = beam_bounds:bounds('rem', {2,3}, any),
+
+    {-1,0} = beam_bounds:bounds('rem', {-1,-1}, any),
+    {-7,0} = beam_bounds:bounds('rem', {-7,-7}, any),
+    {-6,0} = beam_bounds:bounds('rem', {-6,-4}, any),
 
     ok.
 
-- 
2.35.3

openSUSE Build Service is sponsored by