Skip to content
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

Apply type optimizations across local function calls #2100



Copy link

@jhogberg jhogberg commented Jan 21, 2019

The current type pass works on a per-function level and assumes that every argument and return value could be anything, which means they have to be type-checked before they're used. This is a bit inefficient as most functions always return something of the same type, and their argument types seldom differ.

This PR makes the type pass track the return and argument types of local functions, letting us eliminate many redundant type checks.

example1() ->
    %% We no longer check that this is a 2-tuple before extracting A & B
    {A, B} = returns_2_tuple(), 
    A + B.

returns_2_tuple() ->
    {a:a(), b:b()}.

-record(a, {n=0}).

example2() ->
    loop(lists:seq(1, 20), #a{}).

%% Record type is no longer checked on each iteration
loop([I | Is], #a{n=N}=St) ->
    loop(Is, St#a{n=N+I});
loop([], St) ->

A switch is equivalent to a series of '=:=', so we have to subtract
each value individually from the type. Subtracting a join risks
removing too much type information, and managed to narrow "number"
into "float" in the attached test case.
If the match instruction was already marked as a skip, we'd ruin
its argument list.
@jhogberg jhogberg added team:VM Assigned to OTP team VM enhancement labels Jan 21, 2019
@jhogberg jhogberg self-assigned this Jan 21, 2019
@jhogberg jhogberg requested a review from bjorng January 21, 2019 16:02
@jhogberg jhogberg changed the title Apply type optimizations across local functions Apply type optimizations across local function calls Jan 21, 2019
Copy link
Contributor Author

9daffa0 revealed some funny side-effects from propagating the 'none' type across functions. I'm working on fixing them but it might take some time.

@jhogberg jhogberg force-pushed the john/compiler/module-type-optimization branch 3 times, most recently from 9c8b886 to 95a4452 Compare January 23, 2019 14:28
This serves as a base for the upcoming module-level type
optimization, but may come in handy for other passes like
beam_ssa_funs and beam_ssa_bsm that have their own ad-hoc
This commit lets the type optimization pass work across functions,
tracking return and argument types to eliminate redundant tests.
@jhogberg jhogberg force-pushed the john/compiler/module-type-optimization branch from 95a4452 to 294d66a Compare January 24, 2019 07:40
@jhogberg jhogberg merged commit a0104bc into erlang:master Jan 24, 2019
bjorng added a commit to bjorng/otp that referenced this pull request Feb 26, 2021
The `error_handler` module in the Kernel application has a call to the
`int` module in the Debugger application. That call is only there to
make the Debugger work. To avoid that Xref sees Debugger as a
dependency for Kernel, the call to the `int` module is obfuscated in
the following way:

    breakpoint(Module, Func, Args) ->
        (int()):eval(Module, Func, Args).
    int() -> int.

That is, the call will show up as a call to an unknown module in

With the improved whole-module type analysis introduced in
294d66a (erlang#2100), the compiler sees through the obfuscation
and rewrites the code to:

    breakpoint(Module, Func, Args) ->
        int:eval(Module, Func, Args).

It would be fun to solve this issue by introducing further obfuscations,
but such tricks could stop working in the future when the compiler is
improved. Instead, turn off whole-module type analysis by compiling
the module with the `no_module_opt` option.

Resolves erlang#4546
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
enhancement team:VM Assigned to OTP team VM
None yet

Successfully merging this pull request may close these issues.

None yet

2 participants