summaryrefslogtreecommitdiff
path: root/lib/compiler/src
diff options
context:
space:
mode:
authorJohn Högberg <john@erlang.org>2023-04-24 14:12:15 +0200
committerJohn Högberg <john@erlang.org>2023-04-24 16:00:17 +0200
commit8e5b1fbb16d186eb620e4df3470c9cba99885afc (patch)
tree00076728ece7641764c02f0c6c045b6a6b0ac689 /lib/compiler/src
parent039c5deb0d1a1561d6ecd74b8e5e637cff303d6e (diff)
downloaderlang-8e5b1fbb16d186eb620e4df3470c9cba99885afc.tar.gz
beam_bounds: Make 'bnot' converge faster
Fixes #7145
Diffstat (limited to 'lib/compiler/src')
-rw-r--r--lib/compiler/src/beam_bounds.erl23
1 files changed, 22 insertions, 1 deletions
diff --git a/lib/compiler/src/beam_bounds.erl b/lib/compiler/src/beam_bounds.erl
index 6f3902596e..6ac5141821 100644
--- a/lib/compiler/src/beam_bounds.erl
+++ b/lib/compiler/src/beam_bounds.erl
@@ -46,7 +46,28 @@
bounds('bnot', R0) ->
case R0 of
- {A,B} ->
+ {A, B} when is_integer(A), is_integer(B), A =/= B ->
+ %% While it's easy to get an exact range, doing so can make certain
+ %% chains of operations slow to converge, e.g.
+ %%
+ %% f(0) -> -1; f(N) -> abs(bnot f(N)).
+ %%
+ %% Where the range increases by 1 every time we pass through,
+ %% making it more or less impossible to reach a fixpoint.
+ %%
+ %% We therefore widen the range a bit quicker to ensure that we
+ %% converge on 'any' within a reasonable time frame, hoping that
+ %% the range will still be tight enough in the cases where we
+ %% don't feed the result into itself.
+ case {abs(A) bsr ?NUM_BITS, abs(B) bsr ?NUM_BITS} of
+ {0, 0} ->
+ Min = min(-B - 1, -(B bsl 1) - 1),
+ Max = max(-A - 1, -(A bsl 1) - 1),
+ normalize({Min, Max});
+ {_, _} ->
+ any
+ end;
+ {A, B} ->
R = {inf_add(inf_neg(B), -1), inf_add(inf_neg(A), -1)},
normalize(R);
_ ->