File 3135-Enhance-range-analysis-for-the-bor-operator.patch of Package erlang
From 7e33bac60cd7ac8a3f3929d3e976c503407958d3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= <bjorn@erlang.org>
Date: Sun, 13 Aug 2023 07:32:58 +0200
Subject: [PATCH 5/6] Enhance range analysis for the bor operator
Teach beam_bounds:bounds/3 to calculate a range for the `bor` operator
for negative or partly unbounded arguments. For example:
bor0(A) when is_integer(A), -10 =< A, A =< 10 ->
%% Range for A is -10..10
A bor 1. % Range is '-inf'..11
bor1(A, B) when is_integer(A), A < 0, is_integer(B), B < 0 ->
%% Range for A and B is '-inf'..-1
A bor B. % Range is '-inf'..-1
bor2(A, B) when is_integer(A), A >= 1, is_integer(B), B >= 10 ->
%% Range for A is 1..'+inf'; range for B is 10..'+inf'
A bor B. % Range is 10..'+inf'
---
lib/compiler/src/beam_bounds.erl | 39 ++++++++++++++++++-------
lib/compiler/test/beam_bounds_SUITE.erl | 14 +++++++--
2 files changed, 41 insertions(+), 12 deletions(-)
diff --git a/lib/compiler/src/beam_bounds.erl b/lib/compiler/src/beam_bounds.erl
index 034aded4b8..dbe84c566f 100644
--- a/lib/compiler/src/beam_bounds.erl
+++ b/lib/compiler/src/beam_bounds.erl
@@ -156,12 +156,13 @@ bounds('band', R1, R2) ->
end;
bounds('bor', R1, R2) ->
case {R1,R2} of
- {{A,B}, {C,D}} when A bsr ?NUM_BITS =:= 0, A >= 0,
- C bsr ?NUM_BITS =:= 0, C >= 0,
- is_integer(B), is_integer(D) ->
+ {{A,B}, {C,D}} when A =:= '-inf' orelse abs(A) bsr ?NUM_BITS =:= 0,
+ C =:= '-inf' orelse abs(C) bsr ?NUM_BITS =:= 0,
+ B =:= '+inf' orelse abs(B) bsr ?NUM_BITS =:= 0,
+ D =:= '+inf' orelse abs(D) bsr ?NUM_BITS =:= 0 ->
Min = min_bor(A, B, C, D),
Max = max_bor(A, B, C, D),
- {Min,Max};
+ normalize({Min,Max});
{_, _} ->
any
end;
@@ -379,8 +380,13 @@ max_band(A, B, C, D, M) ->
end.
min_bor(A, B, C, D) ->
- M = 1 bsl upper_bit(A bxor C),
- min_bor(A, B, C, D, M).
+ case inf_lt(inf_min(A, C), 0) of
+ true ->
+ '-inf';
+ false ->
+ M = 1 bsl upper_bit(A bxor C),
+ min_bor(A, B, C, D, M)
+ end.
min_bor(A, _B, C, _D, 0) ->
A bor C;
@@ -404,10 +410,23 @@ min_bor(A, B, C, D, M) ->
min_bor(A, B, C, D, M bsr 1)
end.
-max_bor(A, B, C, D) ->
- Intersection = B band D,
- M = 1 bsl upper_bit(Intersection),
- max_bor(Intersection, A, B, C, D, M).
+max_bor(A0, B, C0, D) ->
+ A = inf_max(A0, 0),
+ C = inf_max(C0, 0),
+ case inf_max(B, D) of
+ '+inf' ->
+ '+inf';
+ Max when Max < 0 ->
+ %% Both B and D are negative. The intersection would be
+ %% infinite.
+ -1;
+ _ ->
+ %% At least one of B and D are positive. The intersection
+ %% has a finite size.
+ Intersection = B band D,
+ M = 1 bsl upper_bit(Intersection),
+ max_bor(Intersection, A, B, C, D, M)
+ end.
max_bor(_Intersection, _A, B, _C, D, 0) ->
B bor D;
diff --git a/lib/compiler/test/beam_bounds_SUITE.erl b/lib/compiler/test/beam_bounds_SUITE.erl
index 5f5d2441f1..bee79533b9 100644
--- a/lib/compiler/test/beam_bounds_SUITE.erl
+++ b/lib/compiler/test/beam_bounds_SUITE.erl
@@ -181,8 +181,18 @@ band_bounds(_Config) ->
bor_bounds(_Config) ->
test_commutative('bor'),
- any = beam_bounds:bounds('bor', {-10,0},{-1,10}),
- any = beam_bounds:bounds('bor', {-20,-10}, {-1,10}),
+ {'-inf',15} = beam_bounds:bounds('bor', {-10,7},{3,10}),
+ {'-inf',11} = beam_bounds:bounds('bor', {-10,1},{-1,10}),
+ {'-inf',-1} = beam_bounds:bounds('bor', {-20,-10}, {-2,10}),
+
+ {'-inf',15} = beam_bounds:bounds('bor', {'-inf',10}, {3,5}),
+ {'-inf',-1} = beam_bounds:bounds('bor', {-20,-10}, {-100,-50}),
+
+ any = beam_bounds:bounds('bor', {-20,-10}, {-2,'+inf'}),
+ any = beam_bounds:bounds('bor', {-20,'+inf'}, {-7,-3}),
+
+ {16,'+inf'} = beam_bounds:bounds('bor', {0,8}, {16,'+inf'}),
+ {16,'+inf'} = beam_bounds:bounds('bor', {3,'+inf'}, {16,'+inf'}),
ok.
--
2.35.3