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