Skip to content

Commit ec68721

Browse files
authored
Merge pull request #11480 from bjorng/bjorn/compiler/fix-rem-bounds/GH-11400
Fix bound calculation for the rem operator
2 parents 5d651b9 + b523215 commit ec68721

3 files changed

Lines changed: 49 additions & 22 deletions

File tree

lib/compiler/src/beam_bounds.erl

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -230,28 +230,29 @@ div_bounds({A,B}, _) when is_integer(A), is_integer(B) ->
230230
div_bounds(_, _) ->
231231
any.
232232

233-
rem_bounds({A,_}, {C,D}) when is_integer(C), is_integer(D), C > 0 ->
234-
Max = inf_add(D, -1),
235-
Min = if
236-
A =:= '-inf' -> -Max;
237-
A >= 0 -> 0;
238-
true -> -Max
239-
end,
240-
normalize({Min,Max});
241-
rem_bounds(_, {C,D}) when is_integer(C), is_integer(D),
242-
C =/= 0 orelse D =/= 0 ->
243-
Max = max(abs(C), abs(D)) - 1,
244-
Min = -Max,
245-
normalize({Min,Max});
246-
rem_bounds({A,B}, _) ->
233+
rem_bounds({A,B}, {C,D}) ->
234+
MaxC = inf_max(inf_add(inf_abs(C), -1), 0),
235+
MaxD = inf_max(inf_add(inf_abs(D), -1), 0),
236+
MaxCD = inf_max(MaxC, MaxD),
237+
Min = inf_max(A, inf_neg(MaxCD)),
238+
Max = inf_min(B, MaxCD),
239+
247240
%% The sign of the remainder is the same as the sign of the
248241
%% left-hand side operand; it does not depend on the sign of the
249-
%% right-hand side operand. Therefore, the range of the remainder
250-
%% is the range of the left-hand side operand extended to always
251-
%% include zero.
252-
Min = inf_min(0, A),
253-
Max = inf_max(0, B),
254-
normalize({Min,Max}).
242+
%% right-hand side operand.
243+
case {inf_sign(A),inf_sign(B)} of
244+
{'-','-'} ->
245+
%% The LHS operand is always negative; cap maximum at
246+
%% zero.
247+
normalize({Min,0});
248+
{'-','+'} ->
249+
%% The LHS operand can be negative or positive.
250+
normalize({Min,Max});
251+
{'+','+'} ->
252+
%% The LHS operand is always non-negative; cap minimum at
253+
%% zero.
254+
normalize({0,Max})
255+
end.
255256

256257
min_max_band(A, B, C, D) ->
257258
{Min,Max} = min_max_bor(inf_bnot(B), inf_bnot(A),

lib/compiler/test/beam_bounds_SUITE.erl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,11 +200,14 @@ rem_bounds(_Config) ->
200200

201201
{-7,7} = beam_bounds:bounds('rem', {'-inf',10}, {1,8}),
202202
{0,7} = beam_bounds:bounds('rem', {10,'+inf'}, {1,8}),
203+
{0,9} = beam_bounds:bounds('rem', {10,'+inf'}, {-10,7}),
203204
{0,'+inf'} = beam_bounds:bounds('rem', {17,'+inf'}, any),
205+
{-5,9} = beam_bounds:bounds('rem', {-5,'+inf'}, {-10,7}),
204206

205207
{0,10} = beam_bounds:bounds('rem', {1,10}, {'-inf',10}),
206208
{0,'+inf'} = beam_bounds:bounds('rem', {20,'+inf'}, {10,'+inf'}),
207209
{'-inf',10} = beam_bounds:bounds('rem', {'-inf',10}, any),
210+
{-16,10} = beam_bounds:bounds('rem', {'-inf',10}, {-17,5}),
208211

209212
{-11,10} = beam_bounds:bounds('rem', {-11,10}, {'-inf',89}),
210213
{-11,10} = beam_bounds:bounds('rem', {-11,10}, {7,'+inf'}),
@@ -226,6 +229,13 @@ rem_bounds(_Config) ->
226229
{'-inf',0} = beam_bounds:bounds('rem', {'-inf',-5}, any),
227230
{'-inf',11} = beam_bounds:bounds('rem', {'-inf',11}, any),
228231

232+
{0,1} = beam_bounds:bounds('rem', {1,1}, any),
233+
{0,1} = beam_bounds:bounds('rem', {1,1}, {-10,7}),
234+
{-1,1} = beam_bounds:bounds('rem', {-1,1}, any),
235+
{-1,1} = beam_bounds:bounds('rem', {-1,1}, {-7,10}),
236+
{-2,0} = beam_bounds:bounds('rem', {-2,-1}, any),
237+
{-2,0} = beam_bounds:bounds('rem', {-2,-1}, {-7,10}),
238+
229239
any = beam_bounds:bounds('rem', any, {'-inf',-7}),
230240
any = beam_bounds:bounds('rem', any, {'-inf',0}),
231241
any = beam_bounds:bounds('rem', any, {'-inf',1}),

lib/compiler/test/beam_type_SUITE.erl

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@
3636
cover_maps_functions/1,min_max_mixed_types/1,
3737
not_equal/1,infer_relops/1,binary_unit/1,premature_concretization/1,
3838
funs/1,will_succeed/1,float_confusion/1,
39-
cover_convert_ext/1, catch_setelement/1,gh_11368/1]).
39+
cover_convert_ext/1, catch_setelement/1,gh_11368/1,
40+
rem_bounds/1]).
4041

4142
%% Force id/1 to return 'any'.
4243
-export([id/1]).
@@ -86,7 +87,8 @@ groups() ->
8687
float_confusion,
8788
cover_convert_ext,
8889
catch_setelement,
89-
gh_11368
90+
gh_11368,
91+
rem_bounds
9092
]}].
9193

9294
init_per_suite(Config) ->
@@ -1677,6 +1679,20 @@ prepare_request(Msg0, Seq) ->
16771679
Msg1 = setelement(3, Msg0, [request | Flags]),
16781680
setelement(4, Msg1, Seq).
16791681

1682+
rem_bounds(_Config) ->
1683+
%% Don't call the rem_bounds_1/1 function, because it will never
1684+
%% terminate.
1685+
case id(ignore) of
1686+
call -> rem_bounds_1(1);
1687+
ignore -> ok
1688+
end,
1689+
1690+
ok.
1691+
1692+
%% GH-11400. beam_validator would reject the following code.
1693+
rem_bounds_1(N) ->
1694+
rem_bounds_1((1 rem N) - 2).
1695+
16801696
%%%
16811697
%%% Common utilities.
16821698
%%%

0 commit comments

Comments
 (0)