Skip to content

Commit a7c2109

Browse files
committed
Merge pull request #1926 from pguyot/w43/esp32-embedded-jit
Embedded JIT on RISC-V-based ESP32 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 5b6b9a6 + c4ca8d7 commit a7c2109

12 files changed

Lines changed: 1070 additions & 309 deletions

File tree

libs/jit/src/jit.erl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,6 @@ compile(
137137
MMod,
138138
MSt0
139139
) when OpcodeMax =< ?OPCODE_MAX ->
140-
MSt1 = MMod:jump_table(MSt0, LabelsCount),
141140
State0 = #state{
142141
line_offsets = [],
143142
labels_count = LabelsCount,
@@ -146,6 +145,7 @@ compile(
146145
type_resolver = TypeResolver,
147146
tail_cache = []
148147
},
148+
MSt1 = MMod:jump_table(MSt0, LabelsCount),
149149
{State1, MSt2} = first_pass(Opcodes, MMod, MSt1, State0),
150150
MSt3 = second_pass(MMod, MSt2, State1),
151151
MSt4 = MMod:flush(MSt3),

libs/jit/src/jit_aarch64.erl

Lines changed: 110 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -369,10 +369,67 @@ jump_table0(
369369
N,
370370
LabelsCount
371371
) ->
372-
BranchInstr = jit_aarch64_asm:b(0),
372+
% Placeholder jumps to next entry
373+
BranchInstr = jit_aarch64_asm:b(4),
373374
Stream1 = StreamModule:append(Stream0, BranchInstr),
374375
jump_table0(State#state{stream = Stream1}, N + 1, LabelsCount).
375376

377+
%%-----------------------------------------------------------------------------
378+
%% @doc Patch a single branch in the stream
379+
%% @end
380+
%% @param StreamModule stream module
381+
%% @param Stream stream state
382+
%% @param Offset offset of the branch to patch
383+
%% @param Type type of the branch
384+
%% @param LabelOffset target label offset
385+
%% @return Updated stream
386+
%%-----------------------------------------------------------------------------
387+
-spec patch_branch(module(), stream(), non_neg_integer(), any(), non_neg_integer()) -> stream().
388+
patch_branch(StreamModule, Stream, Offset, Type, LabelOffset) ->
389+
Rel = LabelOffset - Offset,
390+
NewInstr =
391+
case Type of
392+
{bcc, CC} -> jit_aarch64_asm:bcc(CC, Rel);
393+
{adr, Reg} -> jit_aarch64_asm:adr(Reg, Rel);
394+
b -> jit_aarch64_asm:b(Rel)
395+
end,
396+
StreamModule:replace(Stream, Offset, NewInstr).
397+
398+
%%-----------------------------------------------------------------------------
399+
%% @doc Patch all branches targeting a specific label and return remaining branches
400+
%% @end
401+
%% @param StreamModule stream module
402+
%% @param Stream stream state
403+
%% @param TargetLabel label to patch branches for
404+
%% @param LabelOffset offset of the target label
405+
%% @param Branches list of pending branches
406+
%% @return {UpdatedStream, RemainingBranches}
407+
%%-----------------------------------------------------------------------------
408+
-spec patch_branches_for_label(
409+
module(),
410+
stream(),
411+
integer(),
412+
non_neg_integer(),
413+
[{integer(), non_neg_integer(), any()}]
414+
) -> {stream(), [{integer(), non_neg_integer(), any()}]}.
415+
patch_branches_for_label(StreamModule, Stream, TargetLabel, LabelOffset, Branches) ->
416+
patch_branches_for_label(StreamModule, Stream, TargetLabel, LabelOffset, Branches, []).
417+
418+
patch_branches_for_label(_StreamModule, Stream, _TargetLabel, _LabelOffset, [], Acc) ->
419+
{Stream, lists:reverse(Acc)};
420+
patch_branches_for_label(
421+
StreamModule,
422+
Stream0,
423+
TargetLabel,
424+
LabelOffset,
425+
[{Label, Offset, Type} | Rest],
426+
Acc
427+
) when Label =:= TargetLabel ->
428+
Stream1 = patch_branch(StreamModule, Stream0, Offset, Type, LabelOffset),
429+
patch_branches_for_label(StreamModule, Stream1, TargetLabel, LabelOffset, Rest, Acc);
430+
patch_branches_for_label(StreamModule, Stream, TargetLabel, LabelOffset, [Branch | Rest], Acc) ->
431+
patch_branches_for_label(StreamModule, Stream, TargetLabel, LabelOffset, Rest, [Branch | Acc]).
432+
376433
%%-----------------------------------------------------------------------------
377434
%% @doc Rewrite stream to update all branches for labels.
378435
%% @end
@@ -391,14 +448,7 @@ update_branches(
391448
} = State
392449
) ->
393450
{Label, LabelOffset} = lists:keyfind(Label, 1, Labels),
394-
Rel = LabelOffset - Offset,
395-
NewInstr =
396-
case Type of
397-
{bcc, CC} -> jit_aarch64_asm:bcc(CC, Rel);
398-
{adr, Reg} -> jit_aarch64_asm:adr(Reg, Rel);
399-
b -> jit_aarch64_asm:b(Rel)
400-
end,
401-
Stream1 = StreamModule:replace(Stream0, Offset, NewInstr),
451+
Stream1 = patch_branch(StreamModule, Stream0, Offset, Type, LabelOffset),
402452
update_branches(State#state{stream = Stream1, branches = BranchesT}).
403453

404454
%%-----------------------------------------------------------------------------
@@ -1855,17 +1905,30 @@ set_continuation_to_label(
18551905
stream_module = StreamModule,
18561906
stream = Stream0,
18571907
available_regs = [Temp | _],
1858-
branches = Branches
1908+
branches = Branches,
1909+
labels = Labels
18591910
} = State,
18601911
Label
18611912
) ->
18621913
Offset = StreamModule:offset(Stream0),
1863-
I1 = jit_aarch64_asm:adr(Temp, 0),
1864-
Reloc = {Label, Offset, {adr, Temp}},
1865-
I2 = jit_aarch64_asm:str(Temp, ?JITSTATE_CONTINUATION),
1866-
Code = <<I1/binary, I2/binary>>,
1867-
Stream1 = StreamModule:append(Stream0, Code),
1868-
State#state{stream = Stream1, branches = [Reloc | Branches]}.
1914+
case lists:keyfind(Label, 1, Labels) of
1915+
{Label, LabelOffset} ->
1916+
% Label is already known, emit direct adr without relocation
1917+
Rel = LabelOffset - Offset,
1918+
I1 = jit_aarch64_asm:adr(Temp, Rel),
1919+
I2 = jit_aarch64_asm:str(Temp, ?JITSTATE_CONTINUATION),
1920+
Code = <<I1/binary, I2/binary>>,
1921+
Stream1 = StreamModule:append(Stream0, Code),
1922+
State#state{stream = Stream1};
1923+
false ->
1924+
% Label not yet known, emit placeholder and add relocation
1925+
I1 = jit_aarch64_asm:adr(Temp, 0),
1926+
Reloc = {Label, Offset, {adr, Temp}},
1927+
I2 = jit_aarch64_asm:str(Temp, ?JITSTATE_CONTINUATION),
1928+
Code = <<I1/binary, I2/binary>>,
1929+
Stream1 = StreamModule:append(Stream0, Code),
1930+
State#state{stream = Stream1, branches = [Reloc | Branches]}
1931+
end.
18691932

18701933
%%-----------------------------------------------------------------------------
18711934
%% @doc Set the continuation address to the current offset, creating a
@@ -2152,6 +2215,7 @@ call_only_or_schedule_next(
21522215
stream_module = StreamModule,
21532216
stream = Stream0,
21542217
branches = Branches,
2218+
labels = Labels,
21552219
available_regs = [Temp | _]
21562220
} = State0,
21572221
Label
@@ -2164,11 +2228,22 @@ call_only_or_schedule_next(
21642228
I3 = jit_aarch64_asm:str_w(Temp, ?JITSTATE_REDUCTIONCOUNT),
21652229
Stream1 = StreamModule:append(Stream0, <<I1/binary, I2/binary, I3/binary>>),
21662230
BNEOffset = StreamModule:offset(Stream1),
2167-
% Branch to label if reduction count is not zero
2168-
I4 = jit_aarch64_asm:bcc(ne, 0),
2169-
Reloc1 = {Label, BNEOffset, {bcc, ne}},
2170-
Stream2 = StreamModule:append(Stream1, I4),
2171-
State1 = State0#state{stream = Stream2, branches = [Reloc1 | Branches]},
2231+
2232+
case lists:keyfind(Label, 1, Labels) of
2233+
{Label, LabelOffset} ->
2234+
% Label is already known, emit direct branch with calculated offset
2235+
% Calculate relative offset (must be 4-byte aligned)
2236+
Rel = LabelOffset - BNEOffset,
2237+
I4 = jit_aarch64_asm:bcc(ne, Rel),
2238+
Stream2 = StreamModule:append(Stream1, I4),
2239+
State1 = State0#state{stream = Stream2};
2240+
false ->
2241+
% Label not yet known, emit placeholder and add relocation
2242+
I4 = jit_aarch64_asm:bcc(ne, 0),
2243+
Reloc1 = {Label, BNEOffset, {bcc, ne}},
2244+
Stream2 = StreamModule:append(Stream1, I4),
2245+
State1 = State0#state{stream = Stream2, branches = [Reloc1 | Branches]}
2246+
end,
21722247
State2 = set_continuation_to_label(State1, Label),
21732248
call_primitive_last(State2, ?PRIM_SCHEDULE_NEXT_CP, [ctx, jit_state]).
21742249

@@ -2349,6 +2424,7 @@ add_label(
23492424
stream_module = StreamModule,
23502425
stream = Stream0,
23512426
jump_table_start = JumpTableStart,
2427+
branches = Branches,
23522428
labels = Labels
23532429
} = State,
23542430
Label,
@@ -2360,6 +2436,18 @@ add_label(
23602436
RelativeOffset = LabelOffset - JumpTableEntryOffset,
23612437
BranchInstr = jit_aarch64_asm:b(RelativeOffset),
23622438
Stream1 = StreamModule:replace(Stream0, JumpTableEntryOffset, BranchInstr),
2363-
State#state{stream = Stream1, labels = [{Label, LabelOffset} | Labels]};
2439+
2440+
% Eagerly patch any branches targeting this label
2441+
{Stream2, RemainingBranches} = patch_branches_for_label(
2442+
StreamModule,
2443+
Stream1,
2444+
Label,
2445+
LabelOffset,
2446+
Branches
2447+
),
2448+
2449+
State#state{
2450+
stream = Stream2, branches = RemainingBranches, labels = [{Label, LabelOffset} | Labels]
2451+
};
23642452
add_label(#state{labels = Labels} = State, Label, Offset) ->
23652453
State#state{labels = [{Label, Offset} | Labels]}.

libs/jit/src/jit_armv6m.erl

Lines changed: 79 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -405,23 +405,17 @@ jump_table0(
405405
jump_table0(State#state{stream = Stream1}, N + 1, LabelsCount).
406406

407407
%%-----------------------------------------------------------------------------
408-
%% @doc Rewrite stream to update all branches for labels.
408+
%% @doc Patch a single branch in the stream
409409
%% @end
410-
%% @param State current backend state
411-
%% @return Updated backend state
410+
%% @param StreamModule stream module
411+
%% @param Stream stream state
412+
%% @param Offset offset of the branch to patch
413+
%% @param Type type of the branch
414+
%% @param LabelOffset target label offset
415+
%% @return Updated stream
412416
%%-----------------------------------------------------------------------------
413-
-spec update_branches(state()) -> state().
414-
update_branches(#state{branches = []} = State) ->
415-
State;
416-
update_branches(
417-
#state{
418-
stream_module = StreamModule,
419-
stream = Stream0,
420-
branches = [{Label, Offset, Type} | BranchesT],
421-
labels = Labels
422-
} = State
423-
) ->
424-
{Label, LabelOffset} = lists:keyfind(Label, 1, Labels),
417+
-spec patch_branch(module(), stream(), non_neg_integer(), any(), non_neg_integer()) -> stream().
418+
patch_branch(StreamModule, Stream, Offset, Type, LabelOffset) ->
425419
Rel = LabelOffset - Offset,
426420
NewInstr =
427421
case Type of
@@ -497,7 +491,62 @@ update_branches(
497491
end
498492
end
499493
end,
500-
Stream1 = StreamModule:replace(Stream0, Offset, NewInstr),
494+
StreamModule:replace(Stream, Offset, NewInstr).
495+
496+
%%-----------------------------------------------------------------------------
497+
%% @doc Patch all branches targeting a specific label and return remaining branches
498+
%% @end
499+
%% @param StreamModule stream module
500+
%% @param Stream stream state
501+
%% @param TargetLabel label to patch branches for
502+
%% @param LabelOffset offset of the target label
503+
%% @param Branches list of pending branches
504+
%% @return {UpdatedStream, RemainingBranches}
505+
%%-----------------------------------------------------------------------------
506+
-spec patch_branches_for_label(
507+
module(),
508+
stream(),
509+
integer(),
510+
non_neg_integer(),
511+
[{integer(), non_neg_integer(), any()}]
512+
) -> {stream(), [{integer(), non_neg_integer(), any()}]}.
513+
patch_branches_for_label(StreamModule, Stream, TargetLabel, LabelOffset, Branches) ->
514+
patch_branches_for_label(StreamModule, Stream, TargetLabel, LabelOffset, Branches, []).
515+
516+
patch_branches_for_label(_StreamModule, Stream, _TargetLabel, _LabelOffset, [], Acc) ->
517+
{Stream, lists:reverse(Acc)};
518+
patch_branches_for_label(
519+
StreamModule,
520+
Stream0,
521+
TargetLabel,
522+
LabelOffset,
523+
[{Label, Offset, Type} | Rest],
524+
Acc
525+
) when Label =:= TargetLabel ->
526+
Stream1 = patch_branch(StreamModule, Stream0, Offset, Type, LabelOffset),
527+
patch_branches_for_label(StreamModule, Stream1, TargetLabel, LabelOffset, Rest, Acc);
528+
patch_branches_for_label(StreamModule, Stream, TargetLabel, LabelOffset, [Branch | Rest], Acc) ->
529+
patch_branches_for_label(StreamModule, Stream, TargetLabel, LabelOffset, Rest, [Branch | Acc]).
530+
531+
%%-----------------------------------------------------------------------------
532+
%% @doc Rewrite stream to update all branches for labels.
533+
%% @end
534+
%% @param State current backend state
535+
%% @return Updated backend state
536+
%%-----------------------------------------------------------------------------
537+
-spec update_branches(state()) -> state().
538+
update_branches(#state{branches = []} = State) ->
539+
State;
540+
update_branches(
541+
#state{
542+
stream_module = StreamModule,
543+
stream = Stream0,
544+
branches = [{Label, Offset, Type} | BranchesT],
545+
labels = Labels
546+
} = State
547+
) ->
548+
{Label, LabelOffset} = lists:keyfind(Label, 1, Labels),
549+
Stream1 = patch_branch(StreamModule, Stream0, Offset, Type, LabelOffset),
501550
update_branches(State#state{stream = Stream1, branches = BranchesT}).
502551

503552
%%-----------------------------------------------------------------------------
@@ -3282,6 +3331,7 @@ add_label(
32823331
stream_module = StreamModule,
32833332
stream = Stream0,
32843333
jump_table_start = JumpTableStart,
3334+
branches = Branches,
32853335
labels = Labels
32863336
} = State,
32873337
Label,
@@ -3305,6 +3355,18 @@ add_label(
33053355
DataBytes = <<RelativeOffset:32/little>>,
33063356

33073357
Stream1 = StreamModule:replace(Stream0, DataOffset, DataBytes),
3308-
State#state{stream = Stream1, labels = [{Label, LabelOffset} | Labels]};
3358+
3359+
% Eagerly patch any branches targeting this label
3360+
{Stream2, RemainingBranches} = patch_branches_for_label(
3361+
StreamModule,
3362+
Stream1,
3363+
Label,
3364+
LabelOffset,
3365+
Branches
3366+
),
3367+
3368+
State#state{
3369+
stream = Stream2, branches = RemainingBranches, labels = [{Label, LabelOffset} | Labels]
3370+
};
33093371
add_label(#state{labels = Labels} = State, Label, Offset) ->
33103372
State#state{labels = [{Label, Offset} | Labels]}.

0 commit comments

Comments
 (0)