Skip to content

Improve the type analysis #5999

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 27, 2022

Conversation

bjorng
Copy link
Contributor

@bjorng bjorng commented May 19, 2022

Refactor the type analysis modules in the Erlang compiler to
be able to derive type information from relational operators
in guards.

Consider this function:

f(A) when is_integer(A), 0 =< A, A =< 1000 ->
    A + 1.

From the guard, a human can easily figure out that A must be
an integer in the range 0 through 1000. The compiler in OTP 25
cannot:

{test,is_integer,{f,1},[{x,0}]}.
{test,is_ge,{f,1},[{tr,{x,0},{t_integer,any}},{integer,0}]}.
{test,is_ge,{f,1},[{integer,1000},{tr,{x,0},{t_integer,any}}]}.
{gc_bif,'+',{f,0},1,[{tr,{x,0},{t_integer,any}},{integer,1}],{x,0}}.

With this pull request, the compiler generates the following code:

{test,is_integer,{f,1},[{x,0}]}.
{test,is_ge,{f,1},[{tr,{x,0},{t_integer,any}},{integer,0}]}.
{test,is_ge,{f,1},[{integer,1000},{tr,{x,0},{t_integer,{0,'+inf'}}}]}.
{gc_bif,'+',{f,0},1,[{tr,{x,0},{t_integer,{0,1000}}},{integer,1}],{x,0}}.

The compiler can now also derive better types for the following function:

g(A) when 0 =< A, A =< 1000 ->
     A + 1.

Since A is sandwiched between two numbers, A must be a number:

{test,is_ge,{f,3},[{x,0},{integer,0}]}.
{test,is_ge,
      {f,3},
      [{integer,1000},
       {tr,{x,0},
           {t_union,{t_atom,any},
                    {t_list,any,any},
                    {t_number,{0,'+inf'}},
                    {t_tuple,0,false,#{}},
                    other}}]}.
{gc_bif,'+',{f,0},1,[{tr,{x,0},{t_number,{0,1000}}},{integer,1}],{x,0}}.

The JIT will generate slightly better code for known numeric operands than
for unknown operands.

As part of this commit, the following major changes were made:

  • Ranges for integers can now extend to infinity at one endpoint. That
    is, a range can go from negative infinity to some integer, or from
    some integer to positive infinity. That change allows the compiler to
    represent the type for the variable A when A is known to be an
    integer and A >= 0 is true.

  • Changed the number type to also include a (potentially infinite) range.

  • Introduced an other type as a mean to construct a union type that
    is equivalent to the any type. That makes it possible to represent
    the type for A when all we know is that A >= 0 (see the type in
    in the second is_ge test in the generated code for g/1 above).

  • The API for the beam_bounds module was changed to avoid having to
    create functions with the same name as operators and BIFs. Having
    functions named min and max in the module would have been
    error-prone and painful.

@bjorng bjorng added team:VM Assigned to OTP team VM enhancement labels May 19, 2022
@bjorng bjorng self-assigned this May 19, 2022
@github-actions
Copy link
Contributor

github-actions bot commented May 19, 2022

CT Test Results

       4 files     367 suites   43m 42s ⏱️
2 008 tests 1 943 ✔️ 53 💤 12
5 572 runs  5 489 ✔️ 71 💤 12

For more details on these failures, see this check.

Results for commit c412a61.

♻️ This comment has been updated with latest results.

To speed up review, make sure that you have read Contributing to Erlang/OTP and that all checks pass.

See the TESTING and DEVELOPMENT HowTo guides for details about how to run test locally.

Artifacts

// Erlang/OTP Github Action Bot

@bjorng bjorng requested review from jhogberg and lisztspace May 19, 2022 03:20
@kostis
Copy link
Contributor

kostis commented May 19, 2022

From the guard, a human can easily figure out that A must be an integer in the range 0 through 1000.

But isn't this particular human wrong?

(Because A can also be a float. Figuring out that A must be a number is OK though.)

Copy link
Contributor

@jhogberg jhogberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

But isn't this particular human wrong?

(Because A can also be a float. Figuring out that A must be a number is OK though.)

There's an is_integer/1 test hiding in the first example. :-)

@kostis
Copy link
Contributor

kostis commented May 19, 2022

There's an is_integer/1 test hiding in the first example. :-)

Yes, I need new glasses :(

@bjorng bjorng force-pushed the bjorn/compiler/refactor-type-lattice branch from 7dcd4e2 to 249aef8 Compare May 20, 2022 04:02
@bjorng bjorng added the testing currently being tested, tag is used by OTP internal CI label May 20, 2022
@bjorng bjorng force-pushed the bjorn/compiler/refactor-type-lattice branch 3 times, most recently from 098e03a to 431545e Compare May 26, 2022 06:08
Refactor the type analysis modules in the Erlang compiler to
be able to derive type information from relational operators
in guards.

Consider this function:

    f(A) when is_integer(A), 0 =< A, A =< 1000 ->
        A + 1.

From the guard, a human can easily figure out that `A` must be
an integer in the range 0 through 1000. The compiler in OTP 25
cannot:

    {test,is_integer,{f,1},[{x,0}]}.
    {test,is_ge,{f,1},[{tr,{x,0},{t_integer,any}},{integer,0}]}.
    {test,is_ge,{f,1},[{integer,1000},{tr,{x,0},{t_integer,any}}]}.
    {gc_bif,'+',{f,0},1,[{tr,{x,0},{t_integer,any}},{integer,1}],{x,0}}.

With this commit, the compiler generates the following code:

    {test,is_integer,{f,1},[{x,0}]}.
    {test,is_ge,{f,1},[{tr,{x,0},{t_integer,any}},{integer,0}]}.
    {test,is_ge,{f,1},[{integer,1000},{tr,{x,0},{t_integer,{0,'+inf'}}}]}.
    {gc_bif,'+',{f,0},1,[{tr,{x,0},{t_integer,{0,1000}}},{integer,1}],{x,0}}.

The compiler can now also derive better types for the following function:

    g(A) when 0 =< A, A =< 1000 ->
         A + 1.

Since `A` is sandwiched between two numbers, `A` must be a number:

    {test,is_ge,{f,3},[{x,0},{integer,0}]}.
    {test,is_ge,
          {f,3},
          [{integer,1000},
           {tr,{x,0},
               {t_union,{t_atom,any},
                        {t_list,any,any},
                        {t_number,{0,'+inf'}},
                        {t_tuple,0,false,#{}},
                        other}}]}.
    {gc_bif,'+',{f,0},1,[{tr,{x,0},{t_number,{0,1000}}},{integer,1}],{x,0}}.

The JIT will generate slightly better code for known numeric operands than
for unknown operands.

As part of this commit, the following major changes were made:

* Ranges for integers can now extend to infinity at one endpoint. That
  is, a range can go from negative infinity to some integer, or from
  some integer to positive infinity. That change allows the compiler to
  represent the type for the variable `A` when `A` is known to be an
  integer and `A >= 0` is true.

* Changed the number type to also include a (potentially infinite) range.

* Introduced an `other` type as a mean to construct a union type that
  is equivalent to the `any` type. That makes it possible to represent
  the type for `A` when all we know is that `A >= 0` (see the type in
  in the second `is_ge` test in the generated code for `g/1` above).

* The API for the `beam_bounds` module was changed to avoid having to
  create functions with the same name as operators and BIFs. Having
  functions named `min` and `max` in the module would have been
  error-prone and painful.
@bjorng bjorng force-pushed the bjorn/compiler/refactor-type-lattice branch 2 times, most recently from c412a61 to 92611e5 Compare May 27, 2022 05:00
@bjorng bjorng merged commit 4b4a6d2 into erlang:master May 27, 2022
@bjorng bjorng deleted the bjorn/compiler/refactor-type-lattice branch May 27, 2022 05:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement team:VM Assigned to OTP team VM testing currently being tested, tag is used by OTP internal CI
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants