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

Merged

Conversation

@jhogberg
Copy link
Contributor

@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) ->
    St.
jhogberg added 6 commits Jan 21, 2019
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 self-assigned this Jan 21, 2019
@jhogberg jhogberg requested a review from bjorng Jan 21, 2019
@jhogberg jhogberg changed the title Apply type optimizations across local functions Apply type optimizations across local function calls Jan 21, 2019
@jhogberg
Copy link
Contributor Author

@jhogberg jhogberg commented Jan 22, 2019

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 Jan 23, 2019
bjorng
bjorng approved these changes Jan 24, 2019
jhogberg added 2 commits Jan 24, 2019
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
implementations.
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 Jan 24, 2019
@jhogberg jhogberg merged commit a0104bc into erlang:master Jan 24, 2019
1 of 2 checks passed
bjorng added a commit to bjorng/otp that referenced this issue 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
Xref.

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
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

2 participants