|
139 | 139 | available_regs :: [armv6m_register()], |
140 | 140 | used_regs :: [armv6m_register()], |
141 | 141 | labels :: [{integer() | reference(), integer()}], |
142 | | - variant :: non_neg_integer() |
| 142 | + variant :: non_neg_integer(), |
| 143 | + literal_pool :: [{non_neg_integer(), armv6m_register(), non_neg_integer()}] |
143 | 144 | }). |
144 | 145 |
|
145 | 146 | -type state() :: #state{}. |
@@ -252,7 +253,8 @@ new(Variant, StreamModule, Stream) -> |
252 | 253 | available_regs = ?AVAILABLE_REGS, |
253 | 254 | used_regs = [], |
254 | 255 | labels = [], |
255 | | - variant = Variant |
| 256 | + variant = Variant, |
| 257 | + literal_pool = [] |
256 | 258 | }. |
257 | 259 |
|
258 | 260 | %%----------------------------------------------------------------------------- |
@@ -637,7 +639,8 @@ call_primitive_last( |
637 | 639 | State2 = set_registers_args(State1, ArgsForTailCall, 0), |
638 | 640 | tail_call_with_jit_state_registers_only(State2, Temp) |
639 | 641 | end, |
640 | | - State4#state{available_regs = ?AVAILABLE_REGS, used_regs = []}. |
| 642 | + State5 = State4#state{available_regs = ?AVAILABLE_REGS, used_regs = []}, |
| 643 | + flush_literal_pool(State5). |
641 | 644 |
|
642 | 645 | %%----------------------------------------------------------------------------- |
643 | 646 | %% @doc Tail call to address in register, restoring prolog registers including |
@@ -730,13 +733,15 @@ jump_to_label( |
730 | 733 | Offset = StreamModule:offset(Stream0), |
731 | 734 | {State1, CodeBlock} = branch_to_label_code(State0, Offset, Label, LabelLookupResult), |
732 | 735 | Stream1 = StreamModule:append(Stream0, CodeBlock), |
733 | | - State1#state{stream = Stream1}. |
| 736 | + State2 = State1#state{stream = Stream1}, |
| 737 | + flush_literal_pool(State2). |
734 | 738 |
|
735 | 739 | jump_to_offset(#state{stream_module = StreamModule, stream = Stream0} = State, TargetOffset) -> |
736 | 740 | Offset = StreamModule:offset(Stream0), |
737 | 741 | CodeBlock = branch_to_offset_code(State, Offset, TargetOffset), |
738 | 742 | Stream1 = StreamModule:append(Stream0, CodeBlock), |
739 | | - State#state{stream = Stream1}. |
| 743 | + State2 = State#state{stream = Stream1}, |
| 744 | + flush_literal_pool(State2). |
740 | 745 |
|
741 | 746 | %%----------------------------------------------------------------------------- |
742 | 747 | %% @doc Jump to address in continuation pointer register |
@@ -798,7 +803,8 @@ jump_to_continuation( |
798 | 803 | Code = <<I3/binary, I4/binary, I5/binary, I6/binary, I7/binary>>, |
799 | 804 | Stream2 = StreamModule:append(State1#state.stream, Code), |
800 | 805 | % Free all registers as this is a terminal instruction |
801 | | - State1#state{stream = Stream2, available_regs = ?AVAILABLE_REGS, used_regs = []}. |
| 806 | + State2 = State1#state{stream = Stream2, available_regs = ?AVAILABLE_REGS, used_regs = []}, |
| 807 | + flush_literal_pool(State2). |
802 | 808 |
|
803 | 809 | branch_to_offset_code(_State, Offset, TargetOffset) when |
804 | 810 | TargetOffset - Offset =< 2050, TargetOffset - Offset >= -2044 |
@@ -1741,7 +1747,7 @@ set_registers_args( |
1741 | 1747 | UsedRegs, |
1742 | 1748 | Args |
1743 | 1749 | ), |
1744 | | - State0#state{ |
| 1750 | + State1#state{ |
1745 | 1751 | stream = Stream1, |
1746 | 1752 | available_regs = ?AVAILABLE_REGS -- ParamRegs -- NewUsedRegs, |
1747 | 1753 | used_regs = ParamRegs ++ (NewUsedRegs -- ParamRegs) |
@@ -2625,41 +2631,42 @@ mov_immediate(#state{stream_module = StreamModule, stream = Stream0} = State, Re |
2625 | 2631 | I2 = jit_armv6m_asm:negs(Reg, Reg), |
2626 | 2632 | Stream1 = StreamModule:append(Stream0, <<I1/binary, I2/binary>>), |
2627 | 2633 | State#state{stream = Stream1}; |
2628 | | -mov_immediate(#state{stream_module = StreamModule, stream = Stream0} = State, Reg, Val) -> |
2629 | | - %% Use a literal pool with a branch instruction (branch-over pattern) |
2630 | | - %% Calculate where literal will be placed (must be word-aligned) |
2631 | | - %% After LDR (2 bytes) + Branch (2 bytes) = 4 bytes from current position |
2632 | | - CurrentOffset = StreamModule:offset(Stream0), |
2633 | | - OffsetAfterInstructions = CurrentOffset + 4, |
2634 | | - %% Find next word-aligned position for literal |
2635 | | - LiteralPosition = |
2636 | | - case OffsetAfterInstructions rem 4 of |
2637 | | - % Already aligned |
2638 | | - 0 -> OffsetAfterInstructions; |
2639 | | - % Add 2 bytes padding to align |
2640 | | - _ -> OffsetAfterInstructions + 2 |
| 2634 | +mov_immediate( |
| 2635 | + #state{stream_module = StreamModule, stream = Stream0, literal_pool = LP} = State, Reg, Val |
| 2636 | +) -> |
| 2637 | + LdrInstructionAddr = StreamModule:offset(Stream0), |
| 2638 | + I1 = jit_armv6m_asm:ldr(Reg, {pc, 0}), |
| 2639 | + Stream1 = StreamModule:append(Stream0, <<I1/binary>>), |
| 2640 | + State#state{stream = Stream1, literal_pool = [{LdrInstructionAddr, Reg, Val} | LP]}. |
| 2641 | + |
| 2642 | +flush_literal_pool(#state{literal_pool = []} = State) -> |
| 2643 | + State; |
| 2644 | +flush_literal_pool( |
| 2645 | + #state{stream_module = StreamModule, stream = Stream0, literal_pool = LP} = State |
| 2646 | +) -> |
| 2647 | + % Align |
| 2648 | + Offset = StreamModule:offset(Stream0), |
| 2649 | + Stream1 = |
| 2650 | + if |
| 2651 | + Offset rem 4 =:= 0 -> Stream0; |
| 2652 | + true -> StreamModule:append(Stream0, <<0:16>>) |
2641 | 2653 | end, |
2642 | | - PaddingNeeded = LiteralPosition - OffsetAfterInstructions, |
2643 | | - |
2644 | | - %% Calculate LDR PC-relative offset |
2645 | | - %% PC = (current_instruction_address & ~3) + 4 |
2646 | | - LdrInstructionAddr = CurrentOffset, |
2647 | | - LdrPC = (LdrInstructionAddr band (bnot 3)) + 4, |
2648 | | - LiteralOffset = LiteralPosition - LdrPC, |
2649 | | - |
2650 | | - %% Generate: ldr rTemp, [pc, #LiteralOffset] ; Load from literal |
2651 | | - I1 = jit_armv6m_asm:ldr(Reg, {pc, LiteralOffset}), |
2652 | | - %% Calculate branch offset |
2653 | | - %% Branch is at CurrentOffset + 2, need to jump past literal |
2654 | | - BranchPosition = CurrentOffset + 2, |
2655 | | - % After the 4-byte literal |
2656 | | - TargetPosition = LiteralPosition + 4, |
2657 | | - BranchOffset = TargetPosition - BranchPosition, |
2658 | | - I2 = jit_armv6m_asm:b(BranchOffset), |
2659 | | - %% Generate padding if needed (just zeros) |
2660 | | - Padding = <<0:(PaddingNeeded * 8)>>, |
2661 | | - Stream1 = StreamModule:append(Stream0, <<I1/binary, I2/binary, Padding/binary, Val:32/little>>), |
2662 | | - State#state{stream = Stream1}. |
| 2654 | + % Lay all values and update ldr instructions |
| 2655 | + Stream2 = lists:foldl( |
| 2656 | + fun({LdrInstructionAddr, Reg, Val}, AccStream) -> |
| 2657 | + LiteralPosition = StreamModule:offset(AccStream), |
| 2658 | + LdrPC = (LdrInstructionAddr band (bnot 3)) + 4, |
| 2659 | + LiteralOffset = LiteralPosition - LdrPC, |
| 2660 | + LdrInstruction = jit_armv6m_asm:ldr(Reg, {pc, LiteralOffset}), |
| 2661 | + AccStream1 = StreamModule:append(AccStream, <<Val:32/little>>), |
| 2662 | + StreamModule:replace( |
| 2663 | + AccStream1, LdrInstructionAddr, LdrInstruction |
| 2664 | + ) |
| 2665 | + end, |
| 2666 | + Stream1, |
| 2667 | + lists:reverse(LP) |
| 2668 | + ), |
| 2669 | + State#state{stream = Stream2, literal_pool = []}. |
2663 | 2670 |
|
2664 | 2671 | sub(#state{stream_module = StreamModule, stream = Stream0} = State, Reg, Val) when |
2665 | 2672 | (Val >= 0 andalso Val =< 255) orelse is_atom(Val) |
|
0 commit comments