Skip to content

Commit

Permalink
Merge pull request #6651 from jhogberg/john/compiler/propagate-infer-…
Browse files Browse the repository at this point in the history
…relops-failure/GH-6648

compiler: Various type-related fixes and improvements
  • Loading branch information
jhogberg authored Jan 25, 2023
2 parents ac27f7f + 96a1872 commit 2ca36bd
Show file tree
Hide file tree
Showing 7 changed files with 164 additions and 111 deletions.
9 changes: 4 additions & 5 deletions lib/compiler/src/beam_bounds.erl
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
{'-inf', integer()} |
{integer(), '+inf'} |
'any'.
-type range_result() :: range() | 'any'.
-type range_result() :: range() | 'any' | 'none'.
-type relop() :: '<' | '=<' | '>' | '>='.
-type bool_result() :: 'true' | 'false' | 'maybe'.
-type op() :: atom().
Expand Down Expand Up @@ -238,10 +238,9 @@ relop(_, _, _) ->

infer_relop_types(Op, {_,_}=Range1, {_,_}=Range2) ->
case relop(Op, Range1, Range2) of
'maybe' ->
infer_relop_types_1(Op, Range1, Range2);
_ ->
any
'maybe' -> infer_relop_types_1(Op, Range1, Range2);
true -> any;
false -> none
end;
infer_relop_types('<', {A,_}=R1, any) ->
{R1, normalize({inf_add(A, 1), '+inf'})};
Expand Down
104 changes: 63 additions & 41 deletions lib/compiler/src/beam_ssa_type.erl
Original file line number Diff line number Diff line change
Expand Up @@ -2064,8 +2064,9 @@ type(bs_create_bin, Args, _Anno, Ts, _Ds) ->
SizeUnit = bs_size_unit(Args, Ts),
#t_bitstring{size_unit=SizeUnit};
type(bs_extract, [Ctx], _Anno, Ts, Ds) ->
#b_set{op=bs_match,args=Args} = map_get(Ctx, Ds),
bs_match_type(Args, Ts);
#b_set{op=bs_match,
args=[#b_literal{val=Type}, _OrigCtx | Args]} = map_get(Ctx, Ds),
bs_match_type(Type, Args, Ts);
type(bs_start_match, [_, Src], _Anno, Ts, _Ds) ->
case beam_types:meet(#t_bs_matchable{}, concrete_type(Src, Ts)) of
none ->
Expand All @@ -2084,16 +2085,21 @@ type(bs_match, [#b_literal{val=binary}, Ctx, _Flags,
OpType = #t_bs_context{tail_unit=OpUnit},

beam_types:meet(CtxType, OpType);
type(bs_match, Args, _Anno, Ts, _Ds) ->
[_, Ctx | _] = Args,

%% Matches advance the current position without testing the tail unit. We
%% try to retain unit information by taking the GCD of our current unit and
%% the increments we know the match will advance by.
#t_bs_context{tail_unit=CtxUnit} = concrete_type(Ctx, Ts),
OpUnit = bs_match_stride(Args, Ts),
type(bs_match, Args0, _Anno, Ts, _Ds) ->
[#b_literal{val=Type}, Ctx | Args] = Args0, %Assertion.
case bs_match_type(Type, Args, Ts) of
none ->
none;
_ ->
%% Matches advance the current position without testing the tail
%% unit. We try to retain unit information by taking the GCD of our
%% current unit and the increments we know the match will advance
%% by.
#t_bs_context{tail_unit=CtxUnit} = concrete_type(Ctx, Ts),
OpUnit = bs_match_stride(Args, Ts),

#t_bs_context{tail_unit=gcd(OpUnit, CtxUnit)};
#t_bs_context{tail_unit=gcd(OpUnit, CtxUnit)}
end;
type(bs_get_tail, [Ctx], _Anno, Ts, _Ds) ->
#t_bs_context{tail_unit=Unit} = concrete_type(Ctx, Ts),
#t_bitstring{size_unit=Unit};
Expand Down Expand Up @@ -2341,38 +2347,50 @@ bs_match_stride(_, _, _) ->

-define(UNICODE_MAX, (16#10FFFF)).

bs_match_type([#b_literal{val=Type}|Args], Ts) ->
bs_match_type(Type, Args, Ts).

bs_match_type(binary, Args, _Ts) ->
[_,_,_,#b_literal{val=U}] = Args,
[_,_,#b_literal{val=U}] = Args,
#t_bitstring{size_unit=U};
bs_match_type(float, _, _Ts) ->
bs_match_type(float, _Args, _Ts) ->
#t_float{};
bs_match_type(integer, Args, Ts) ->
[_,#b_literal{val=Flags},Size,#b_literal{val=Unit}] = Args,
SizeType = beam_types:meet(concrete_type(Size, Ts), #t_integer{}),
case SizeType of
#t_integer{elements={_,SizeMax}}
when is_integer(SizeMax), SizeMax >= 0, SizeMax * Unit < 64 ->
NumBits = SizeMax * Unit,
Max = (1 bsl NumBits) - 1,
case member(unsigned, Flags) of
true ->
beam_types:make_integer(0, Max);
false ->
Min = -(Max + 1),
beam_types:make_integer(Min, Max)
[#b_literal{val=Flags},Size,#b_literal{val=Unit}] = Args,
case beam_types:meet(concrete_type(Size, Ts), #t_integer{}) of
#t_integer{elements=Bounds} ->
case beam_bounds:bounds('*', Bounds, {Unit, Unit}) of
{_, MaxBits} when is_integer(MaxBits),
MaxBits >= 1,
MaxBits =< 64 ->
case member(unsigned, Flags) of
true ->
Max = (1 bsl MaxBits) - 1,
beam_types:make_integer(0, Max);
false ->
Max = (1 bsl (MaxBits - 1)) - 1,
Min = -(Max + 1),
beam_types:make_integer(Min, Max)
end;
{_, 0} ->
beam_types:make_integer(0);
_ ->
case member(unsigned, Flags) of
true -> #t_integer{elements={0,'+inf'}};
false -> #t_integer{}
end
end;
_ ->
#t_integer{}
none ->
none
end;
bs_match_type(utf8, _, _) ->

bs_match_type(utf8, _Args, _Ts) ->
beam_types:make_integer(0, ?UNICODE_MAX);
bs_match_type(utf16, _Args, _Ts) ->
beam_types:make_integer(0, ?UNICODE_MAX);
bs_match_type(utf16, _, _) ->
bs_match_type(utf32, _Args, _Ts) ->
beam_types:make_integer(0, ?UNICODE_MAX);
bs_match_type(utf32, _, _) ->
beam_types:make_integer(0, ?UNICODE_MAX).
bs_match_type(string, _Args, _Ts) ->
%% Cannot actually be extracted, but we'll return 'any' to signal that the
%% associated `bs_match` may succeed.
any.

normalized_types(Values, Ts) ->
[normalized_type(Val, Ts) || Val <- Values].
Expand Down Expand Up @@ -2508,11 +2526,13 @@ infer_relop(Op, [Arg1,Arg2], Types0) ->
infer_relop(Op, [#t_integer{elements=R1},
#t_integer{elements=R2}]) ->
case beam_bounds:infer_relop_types(Op, R1, R2) of
any ->
any;
{NewR1,NewR2} ->
{#t_integer{elements=NewR1},
#t_integer{elements=NewR2}}
#t_integer{elements=NewR2}};
none ->
{none, none};
any ->
any
end;
infer_relop(Op0, [Type1,Type2]) ->
Op = case Op0 of
Expand All @@ -2530,11 +2550,13 @@ infer_relop(Op0, [Type1,Type2]) ->
{R1,R2} ->
%% Both operands are numeric types.
case beam_bounds:infer_relop_types(Op, R1, R2) of
any ->
any;
{NewR1,NewR2} ->
{#t_number{elements=NewR1},
#t_number{elements=NewR2}}
#t_number{elements=NewR2}};
none ->
{none, none};
any ->
any
end
end.

Expand Down
2 changes: 2 additions & 0 deletions lib/compiler/src/beam_types.erl
Original file line number Diff line number Diff line change
Expand Up @@ -1413,6 +1413,7 @@ ext_type_mapping() ->

-spec decode_ext(binary()) -> {type(),binary()} | 'done'.
decode_ext(<<TypeBits:16/big,More/binary>>) ->
true = TypeBits =/= 0, %Assertion.
Res = foldl(fun({Id, Type}, Acc) ->
decode_ext_bits(TypeBits, Id, Type, Acc)
end, none, ext_type_mapping()),
Expand Down Expand Up @@ -1474,6 +1475,7 @@ encode_ext(Input) ->
end, 0, ext_type_mapping()),
{TypeBits1,Extra} = encode_extra(Input),
TypeBits = TypeBits0 bor TypeBits1,
true = TypeBits =/= 0, %Assertion.
<<TypeBits:16,Extra/binary>>.

encode_ext_bits(Input, TypeBit, Type, Acc) ->
Expand Down
Loading

0 comments on commit 2ca36bd

Please sign in to comment.