@@ -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+ };
23642452add_label (# state {labels = Labels } = State , Label , Offset ) ->
23652453 State # state {labels = [{Label , Offset } | Labels ]}.
0 commit comments