From c5979b0d6c491ae70e6866abaeeaba40d596b00f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Mon, 14 Aug 2023 05:36:41 +0200 Subject: [PATCH] Enhance range analysis for the * operator 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' --- lib/compiler/src/beam_bounds.erl | 3 +++ lib/compiler/src/beam_call_types.erl | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/lib/compiler/src/beam_bounds.erl b/lib/compiler/src/beam_bounds.erl index dbe84c566f15..cfa6e4d37877 100644 --- a/lib/compiler/src/beam_bounds.erl +++ b/lib/compiler/src/beam_bounds.erl @@ -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, diff --git a/lib/compiler/src/beam_call_types.erl b/lib/compiler/src/beam_call_types.erl index ca05d04d1d86..222e586a7943 100644 --- a/lib/compiler/src/beam_call_types.erl +++ b/lib/compiler/src/beam_call_types.erl @@ -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{} ->