Skip to content

Commit cba052c

Browse files
committed
Merge pull request #2322 from pguyot/w22/jit-compiler-optimizations
JIT compile-time optimizations These changes are made under both the "Apache 2.0" and the "GNU Lesser General Public License 2.1 or later" license terms (dual license). SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
2 parents 642dda8 + 1fffaae commit cba052c

10 files changed

Lines changed: 457 additions & 347 deletions

libs/jit/src/jit.erl

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -99,17 +99,22 @@
9999
tail_cache :: tail_cache()
100100
}).
101101

102-
-type tail_cache() :: [{tuple(), non_neg_integer()}] | disabled.
102+
-type tail_cache() :: #{tuple() => non_neg_integer()} | disabled.
103103
-type stream() :: any().
104104

105105
%%-define(TRACE(Fmt, Args), io:format(Fmt, Args)).
106106
-define(TRACE(Fmt, Args), ok).
107107

108-
tail_cache_find(_Key, disabled) -> false;
109-
tail_cache_find(Key, TC) -> lists:keyfind(Key, 1, TC).
108+
tail_cache_find(_Key, disabled) ->
109+
false;
110+
tail_cache_find(Key, TC) ->
111+
case TC of
112+
#{Key := Value} -> {Key, Value};
113+
_ -> false
114+
end.
110115

111116
tail_cache_store(_Key, _Value, disabled) -> disabled;
112-
tail_cache_store(Key, Value, TC) -> [{Key, Value} | TC].
117+
tail_cache_store(Key, Value, TC) -> TC#{Key => Value}.
113118

114119
%%-define(ASSERT_ALL_NATIVE_FREE(St), MMod:assert_all_native_free(St)).
115120
%%-define(ASSERT(Expr), true = Expr).
@@ -154,11 +159,11 @@ compile(
154159
case erlang:function_exported(MMod, supports_tail_cache, 0) of
155160
true ->
156161
case MMod:supports_tail_cache() of
157-
true -> [];
162+
true -> #{};
158163
false -> disabled
159164
end;
160165
false ->
161-
[]
166+
#{}
162167
end
163168
},
164169
MSt1 = MMod:jump_table(MSt0, LabelsCount),

libs/jit/src/jit_aarch64.erl

Lines changed: 74 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -154,11 +154,11 @@
154154
stream_module :: module(),
155155
stream :: stream(),
156156
offset :: non_neg_integer(),
157-
branches :: [{non_neg_integer(), non_neg_integer(), non_neg_integer()}],
157+
branches :: #{integer() | reference() => [{non_neg_integer(), non_neg_integer()}]},
158158
jump_table_start :: non_neg_integer(),
159159
available_regs :: non_neg_integer(),
160160
used_regs :: non_neg_integer(),
161-
labels :: [{integer() | reference(), integer()}],
161+
labels :: #{integer() | reference() => integer()},
162162
variant :: non_neg_integer(),
163163
regs :: jit_regs:regs()
164164
}).
@@ -286,12 +286,12 @@ new(Variant, StreamModule, Stream) ->
286286
#state{
287287
stream_module = StreamModule,
288288
stream = Stream,
289-
branches = [],
289+
branches = #{},
290290
jump_table_start = 0,
291291
offset = StreamModule:offset(Stream),
292292
available_regs = ?AVAILABLE_REGS_MASK,
293293
used_regs = 0,
294-
labels = [],
294+
labels = #{},
295295
variant = Variant,
296296
regs = jit_regs:new()
297297
}.
@@ -465,27 +465,25 @@ patch_branch(StreamModule, Stream, Offset, Type, LabelOffset) ->
465465
-spec patch_branches_for_label(
466466
module(),
467467
stream(),
468-
integer(),
468+
integer() | reference(),
469469
non_neg_integer(),
470-
[{integer(), non_neg_integer(), any()}]
471-
) -> {stream(), [{integer(), non_neg_integer(), any()}]}.
470+
#{integer() | reference() => [{non_neg_integer(), non_neg_integer()}]}
471+
) ->
472+
{stream(), #{integer() | reference() => [{non_neg_integer(), non_neg_integer()}]}}.
472473
patch_branches_for_label(StreamModule, Stream, TargetLabel, LabelOffset, Branches) ->
473-
patch_branches_for_label(StreamModule, Stream, TargetLabel, LabelOffset, Branches, []).
474-
475-
patch_branches_for_label(_StreamModule, Stream, _TargetLabel, _LabelOffset, [], Acc) ->
476-
{Stream, lists:reverse(Acc)};
477-
patch_branches_for_label(
478-
StreamModule,
479-
Stream0,
480-
TargetLabel,
481-
LabelOffset,
482-
[{Label, Offset, Type} | Rest],
483-
Acc
484-
) when Label =:= TargetLabel ->
485-
Stream1 = patch_branch(StreamModule, Stream0, Offset, Type, LabelOffset),
486-
patch_branches_for_label(StreamModule, Stream1, TargetLabel, LabelOffset, Rest, Acc);
487-
patch_branches_for_label(StreamModule, Stream, TargetLabel, LabelOffset, [Branch | Rest], Acc) ->
488-
patch_branches_for_label(StreamModule, Stream, TargetLabel, LabelOffset, Rest, [Branch | Acc]).
474+
case Branches of
475+
#{TargetLabel := BrList} ->
476+
Stream1 = lists:foldl(
477+
fun({Offset, Type}, AccStream) ->
478+
patch_branch(StreamModule, AccStream, Offset, Type, LabelOffset)
479+
end,
480+
Stream,
481+
BrList
482+
),
483+
{Stream1, maps:remove(TargetLabel, Branches)};
484+
_ ->
485+
{Stream, Branches}
486+
end.
489487

490488
%%-----------------------------------------------------------------------------
491489
%% @doc Rewrite stream to update all branches for labels.
@@ -494,19 +492,29 @@ patch_branches_for_label(StreamModule, Stream, TargetLabel, LabelOffset, [Branch
494492
%% @return Updated backend state
495493
%%-----------------------------------------------------------------------------
496494
-spec update_branches(state()) -> state().
497-
update_branches(#state{branches = []} = State) ->
498-
State;
499495
update_branches(
500496
#state{
501497
stream_module = StreamModule,
502498
stream = Stream0,
503-
branches = [{Label, Offset, Type} | BranchesT],
499+
branches = Branches,
504500
labels = Labels
505501
} = State
506502
) ->
507-
{Label, LabelOffset} = lists:keyfind(Label, 1, Labels),
508-
Stream1 = patch_branch(StreamModule, Stream0, Offset, Type, LabelOffset),
509-
update_branches(State#state{stream = Stream1, branches = BranchesT}).
503+
Stream1 = maps:fold(
504+
fun(Label, BrList, AccStream) ->
505+
#{Label := LabelOffset} = Labels,
506+
lists:foldl(
507+
fun({Offset, Type}, AccStream2) ->
508+
patch_branch(StreamModule, AccStream2, Offset, Type, LabelOffset)
509+
end,
510+
AccStream,
511+
BrList
512+
)
513+
end,
514+
Stream0,
515+
Branches
516+
),
517+
State#state{stream = Stream1, branches = #{}}.
510518

511519
%%-----------------------------------------------------------------------------
512520
%% @doc Emit a call (call with return) to a primitive with arguments. This
@@ -650,21 +658,22 @@ jump_to_label(
650658
Label
651659
) ->
652660
Offset = StreamModule:offset(Stream0),
653-
case lists:keyfind(Label, 1, Labels) of
654-
{Label, LabelOffset} ->
661+
case Labels of
662+
#{Label := LabelOffset} ->
655663
% Label is already known, emit direct branch without relocation
656664
Rel = LabelOffset - Offset,
657665
I1 = jit_aarch64_asm:b(Rel),
658666
Stream1 = StreamModule:append(Stream0, I1),
659667
State#state{stream = Stream1, regs = jit_regs:unreachable(State#state.regs)};
660-
false ->
668+
_ ->
661669
% Label not yet known, emit placeholder and add relocation
662670
I1 = jit_aarch64_asm:b(0),
663-
Reloc = {Label, Offset, b},
671+
BrEntry = {Offset, b},
672+
ExistingBrs = maps:get(Label, AccBranches, []),
664673
Stream1 = StreamModule:append(Stream0, I1),
665674
State#state{
666675
stream = Stream1,
667-
branches = [Reloc | AccBranches],
676+
branches = AccBranches#{Label => [BrEntry | ExistingBrs]},
668677
regs = jit_regs:unreachable(State#state.regs)
669678
}
670679
end.
@@ -2386,21 +2395,26 @@ set_continuation_to_label(
23862395
Temp = first_avail(Avail),
23872396
Offset = StreamModule:offset(Stream0),
23882397
Regs1 = jit_regs:invalidate_reg(Regs0, Temp),
2389-
case lists:keyfind(Label, 1, Labels) of
2390-
{Label, LabelOffset} ->
2398+
case Labels of
2399+
#{Label := LabelOffset} ->
23912400
Rel = LabelOffset - Offset,
23922401
I1 = jit_aarch64_asm:adr(Temp, Rel),
23932402
I2 = jit_aarch64_asm:str(Temp, ?JITSTATE_CONTINUATION),
23942403
Code = <<I1/binary, I2/binary>>,
23952404
Stream1 = StreamModule:append(Stream0, Code),
23962405
State#state{stream = Stream1, regs = Regs1};
2397-
false ->
2406+
_ ->
23982407
I1 = jit_aarch64_asm:adr(Temp, 0),
2399-
Reloc = {Label, Offset, {adr, Temp}},
2408+
BrEntry = {Offset, {adr, Temp}},
24002409
I2 = jit_aarch64_asm:str(Temp, ?JITSTATE_CONTINUATION),
24012410
Code = <<I1/binary, I2/binary>>,
24022411
Stream1 = StreamModule:append(Stream0, Code),
2403-
State#state{stream = Stream1, branches = [Reloc | Branches], regs = Regs1}
2412+
ExistingBrs = maps:get(Label, Branches, []),
2413+
State#state{
2414+
stream = Stream1,
2415+
branches = Branches#{Label => [BrEntry | ExistingBrs]},
2416+
regs = Regs1
2417+
}
24042418
end.
24052419

24062420
%%-----------------------------------------------------------------------------
@@ -2425,12 +2439,19 @@ set_continuation_to_offset(
24252439
OffsetRef = make_ref(),
24262440
Offset = StreamModule:offset(Stream0),
24272441
I1 = jit_aarch64_asm:adr(Temp, 0),
2428-
Reloc = {OffsetRef, Offset, {adr, Temp}},
2442+
BrEntry = {Offset, {adr, Temp}},
24292443
I2 = jit_aarch64_asm:str(Temp, ?JITSTATE_CONTINUATION),
24302444
Code = <<I1/binary, I2/binary>>,
24312445
Stream1 = StreamModule:append(Stream0, Code),
24322446
Regs1 = jit_regs:invalidate_reg(Regs0, Temp),
2433-
{State#state{stream = Stream1, branches = [Reloc | Branches], regs = Regs1}, OffsetRef}.
2447+
{
2448+
State#state{
2449+
stream = Stream1,
2450+
branches = Branches#{OffsetRef => [BrEntry]},
2451+
regs = Regs1
2452+
},
2453+
OffsetRef
2454+
}.
24342455

24352456
%%-----------------------------------------------------------------------------
24362457
%% @doc Implement a continuation entry point. On AArch64 this is a nop
@@ -2815,20 +2836,24 @@ call_only_or_schedule_next(
28152836
Stream1 = StreamModule:append(Stream0, <<I1/binary, I2/binary, I3/binary>>),
28162837
BNEOffset = StreamModule:offset(Stream1),
28172838

2818-
case lists:keyfind(Label, 1, Labels) of
2819-
{Label, LabelOffset} ->
2839+
case Labels of
2840+
#{Label := LabelOffset} ->
28202841
% Label is already known, emit direct branch with calculated offset
28212842
% Calculate relative offset (must be 4-byte aligned)
28222843
Rel = LabelOffset - BNEOffset,
28232844
I4 = jit_aarch64_asm:bcc(ne, Rel),
28242845
Stream2 = StreamModule:append(Stream1, I4),
28252846
State1 = State0#state{stream = Stream2};
2826-
false ->
2847+
_ ->
28272848
% Label not yet known, emit placeholder and add relocation
28282849
I4 = jit_aarch64_asm:bcc(ne, 0),
2829-
Reloc1 = {Label, BNEOffset, {bcc, ne}},
2850+
BrEntry = {BNEOffset, {bcc, ne}},
2851+
ExistingBrs = maps:get(Label, Branches, []),
28302852
Stream2 = StreamModule:append(Stream1, I4),
2831-
State1 = State0#state{stream = Stream2, branches = [Reloc1 | Branches]}
2853+
State1 = State0#state{
2854+
stream = Stream2,
2855+
branches = Branches#{Label => [BrEntry | ExistingBrs]}
2856+
}
28322857
end,
28332858
State2 = set_continuation_to_label(State1, Label),
28342859
call_primitive_last(State2, ?PRIM_SCHEDULE_NEXT_CP, [ctx, jit_state]).
@@ -2926,7 +2951,7 @@ return_labels_and_lines(
29262951
) ->
29272952
SortedLabels = lists:keysort(2, [
29282953
{Label, LabelOffset}
2929-
|| {Label, LabelOffset} <- Labels, is_integer(Label)
2954+
|| {Label, LabelOffset} <- maps:to_list(Labels), is_integer(Label)
29302955
]),
29312956

29322957
I1 = jit_aarch64_asm:adr(r0, 8),
@@ -3081,10 +3106,10 @@ add_label(
30813106
),
30823107

30833108
State#state{
3084-
stream = Stream2, branches = RemainingBranches, labels = [{Label, LabelOffset} | Labels]
3109+
stream = Stream2, branches = RemainingBranches, labels = Labels#{Label => LabelOffset}
30853110
};
30863111
add_label(#state{labels = Labels} = State, Label, Offset) ->
3087-
State#state{labels = [{Label, Offset} | Labels]}.
3112+
State#state{labels = Labels#{Label => Offset}}.
30883113

30893114
-ifdef(JIT_DWARF).
30903115
%%-----------------------------------------------------------------------------

0 commit comments

Comments
 (0)