Skip to content

Commit

Permalink
Enhance range analysis for the * operator
Browse files Browse the repository at this point in the history
Teach beam_bounds:bound/3 to determine a range for the `*` operator
when both factors have a non-negative lower bound. For example:

    m(A, B) when is_integer(A), A >= 2, is_integer(B), B >= 10 ->
        %% Range for A is 2..'+inf'; range for B is 10..'+inf'
        A * B < 100.            % Range for A * B is 20..'+inf'
  • Loading branch information
bjorng committed Aug 15, 2023
1 parent 7e33bac commit c5979b0
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 0 deletions.
3 changes: 3 additions & 0 deletions lib/compiler/src/beam_bounds.erl
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ bounds('*', R1, R2) ->
Min = lists:min(All),
Max = lists:max(All),
normalize({Min,Max});
{{A,'+inf'}, {C,'+inf'}} when abs(A) bsr ?NUM_BITS =:= 0, A >= 0,
abs(C) bsr ?NUM_BITS =:= 0, C >= 0 ->
{A*C,'+inf'};
{{A,'+inf'}, {C,D}} when abs(A) bsr ?NUM_BITS =:= 0,
abs(C) bsr ?NUM_BITS =:= 0,
abs(D) bsr ?NUM_BITS =:= 0,
Expand Down
18 changes: 18 additions & 0 deletions lib/compiler/src/beam_call_types.erl
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,24 @@ types(erlang, Op, [LHS, RHS]) when Op =:= '+'; Op =:= '-' ->
mixed_arith_types([LHS, RHS])
end;

types(erlang, '*', [LHS, RHS]) ->
case get_range(LHS, RHS, #t_number{}) of
{Type, {A,B}, {C,D}} ->
case beam_bounds:bounds('*', {A,B}, {C,D}) of
{Min,_Max} when is_integer(Min), Min >= 0 ->
R = {Min,'+inf'},
RetType = case Type of
integer -> #t_integer{elements=R};
number -> #t_number{elements=R}
end,
sub_unsafe(RetType, [#t_number{}, #t_number{}]);
_ ->
mixed_arith_types([LHS, RHS])
end;
_ ->
mixed_arith_types([LHS, RHS])
end;

types(erlang, abs, [Type]) ->
case meet(Type, #t_number{}) of
#t_float{} ->
Expand Down

0 comments on commit c5979b0

Please sign in to comment.