@@ -317,7 +317,7 @@ flush(#state{stream_module = StreamModule, stream = Stream0} = State) ->
317317% %-----------------------------------------------------------------------------
318318-spec debugger (state ()) -> state ().
319319debugger (# state {stream_module = StreamModule , stream = Stream0 } = State ) ->
320- Stream1 = StreamModule :append (Stream0 , jit_riscv32_asm :bkpt ( 0 )),
320+ Stream1 = StreamModule :append (Stream0 , jit_riscv32_asm :c_ebreak ( )),
321321 State # state {stream = Stream1 }.
322322
323323% %-----------------------------------------------------------------------------
@@ -416,12 +416,7 @@ jump_table0(
416416 % Create jump table entry: AUIPC + JALR (8 bytes total)
417417 % This will be patched later in update_branches/2
418418 Offset = StreamModule :offset (Stream0 ),
419- % Placeholder: Load PC + upper20 bits
420- I1 = jit_riscv32_asm :auipc (a3 , 0 ),
421- % Placeholder: Jump to a3 + lower12 bits
422- I2 = jit_riscv32_asm :jalr (zero , a3 , 0 ),
423-
424- JumpEntry = <<I1 /binary , I2 /binary >>,
419+ JumpEntry = <<16#FFFFFFFF :32 , 16#FFFFFFFF :32 >>,
425420 Stream1 = StreamModule :append (Stream0 , JumpEntry ),
426421
427422 % Record both AUIPC and JALR offsets for patching
@@ -451,30 +446,49 @@ update_branches(
451446 Rel = LabelOffset - Offset ,
452447 NewInstr =
453448 case Type of
454- {adr , Reg } when Rel rem 4 =:= 0 -> pc_relative_address (Reg , Rel );
455- {adr , Reg } when Rel rem 4 =:= 2 -> pc_relative_address (Reg , Rel + 2 );
456- {far_branch , Size , TempReg } ->
449+ {adr , Reg } when Rel rem 4 =:= 0 ->
450+ % Generate pc_relative_address and pad to 8 bytes with NOP
451+ I = pc_relative_address (Reg , Rel ),
452+ case byte_size (I ) of
453+ 4 -> <<I /binary , (jit_riscv32_asm :nop ())/binary >>;
454+ 6 -> <<I /binary , (jit_riscv32_asm :c_nop ())/binary >>;
455+ 8 -> I
456+ end ;
457+ {adr , Reg } when Rel rem 4 =:= 2 ; Rel rem 4 =:= - 2 ->
458+ % Handle 2-byte aligned offsets and pad to 8 bytes
459+ % Handle both positive and negative offsets (Erlang rem can be negative)
460+ I = pc_relative_address (Reg , Rel ),
461+ case byte_size (I ) of
462+ 4 -> <<I /binary , (jit_riscv32_asm :nop ())/binary >>;
463+ 6 -> <<I /binary , (jit_riscv32_asm :c_nop ())/binary >>;
464+ 8 -> I
465+ end ;
466+ {far_branch , TempReg } ->
457467 % Check if branch can now be optimized to near branch
458468 if
459469 Rel >= - 1048576 andalso Rel =< 1048574 andalso (Rel rem 2 ) =:= 0 ->
460470 % RISC-V jal has ±1MB range
461471 % Optimize to near branch: jal + nops to fill original size
462472 DirectBranch = jit_riscv32_asm :jal (zero , Rel ),
463- % Fill remaining bytes with NOPs (RISC-V instructions are 4 bytes)
464- NopCount = ( Size - 4 ) div 4 ,
465- Nops = <<
466- << (jit_riscv32_asm :nop ())/binary >>
467- || _ <- lists : seq ( 1 , NopCount )
468- >>,
469- << DirectBranch / binary , Nops / binary >> ;
473+ case byte_size ( DirectBranch ) of
474+ 2 ->
475+ << DirectBranch / binary , ( jit_riscv32_asm : c_nop ())/ binary ,
476+ (jit_riscv32_asm :nop ())/binary >>;
477+ 4 ->
478+ << DirectBranch / binary , ( jit_riscv32_asm : nop ())/ binary >>
479+ end ;
470480 true ->
471481 % Keep far branch sequence: auipc + jalr (PC-relative, 8 bytes)
472482 % Split the relative offset into upper 20 bits and lower 12 bits
473483 Hi20 = (Rel + 16#800 ) bsr 12 ,
474484 Lo12 = Rel - (Hi20 bsl 12 ),
475485 I1 = jit_riscv32_asm :auipc (TempReg , Hi20 ),
476486 I2 = jit_riscv32_asm :jalr (zero , TempReg , Lo12 ),
477- <<I1 /binary , I2 /binary >>
487+ Entry = <<I1 /binary , I2 /binary >>,
488+ case byte_size (Entry ) of
489+ 6 -> <<Entry /binary , (jit_riscv32_asm :c_nop ())/binary >>;
490+ 8 -> Entry
491+ end
478492 end ;
479493 jump_table_auipc_jalr ->
480494 % Calculate PC-relative offset from AUIPC instruction to target
@@ -498,7 +512,12 @@ update_branches(
498512 % Encode AUIPC and JALR with computed offsets
499513 I1 = jit_riscv32_asm :auipc (a3 , Upper20 ),
500514 I2 = jit_riscv32_asm :jalr (zero , a3 , Lower12Signed ),
501- <<I1 /binary , I2 /binary >>
515+ % Map to 8 bytes
516+ JumpTableEntry = <<I1 /binary , I2 /binary >>,
517+ case byte_size (JumpTableEntry ) of
518+ 6 -> <<JumpTableEntry /binary , (jit_riscv32_asm :c_nop ())/binary >>;
519+ 8 -> JumpTableEntry
520+ end
502521 end ,
503522 Stream1 = StreamModule :replace (Stream0 , Offset , NewInstr ),
504523 update_branches (State # state {stream = Stream1 , branches = BranchesT }).
@@ -783,13 +802,10 @@ branch_to_label_code(
783802 % RISC-V: Far branch sequence using PC-relative auipc + jalr (8 bytes)
784803
785804 % Placeholder: auipc TempReg, 0
786- I1 = jit_riscv32_asm :auipc (TempReg , 0 ),
787805 % Placeholder: jalr zero, TempReg, 0
788- I2 = jit_riscv32_asm :jalr (zero , TempReg , 0 ),
789- CodeBlock = <<I1 /binary , I2 /binary >>,
790- SequenceSize = byte_size (CodeBlock ),
806+ CodeBlock = <<16#FFFFFFFF :32 , 16#FFFFFFFF :32 >>,
791807 % Add relocation entry
792- Reloc = {Label , Offset , {far_branch , SequenceSize , TempReg }},
808+ Reloc = {Label , Offset , {far_branch , TempReg }},
793809 State1 = State0 # state {branches = [Reloc | Branches ]},
794810 {State1 , CodeBlock };
795811branch_to_label_code (
@@ -799,13 +815,10 @@ branch_to_label_code(
799815 % Far branch sequence using PC-relative auipc + jalr (8 bytes)
800816
801817 % Placeholder: auipc t6, 0
802- I1 = jit_riscv32_asm :auipc (t6 , 0 ),
803818 % Placeholder: jalr zero, t6, 0
804- I2 = jit_riscv32_asm :jalr (zero , t6 , 0 ),
805- CodeBlock = <<I1 /binary , I2 /binary >>,
806- SequenceSize = byte_size (CodeBlock ),
819+ CodeBlock = <<16#FFFFFFFF :32 , 16#FFFFFFFF :32 >>,
807820 % Add relocation entry
808- Reloc = {Label , Offset , {far_branch , SequenceSize , t6 }},
821+ Reloc = {Label , Offset , {far_branch , t6 }},
809822 State1 = State0 # state {branches = [Reloc | Branches ]},
810823 {State1 , CodeBlock };
811824branch_to_label_code (# state {available_regs = []}, _Offset , _Label , _LabelLookup ) ->
@@ -1671,19 +1684,8 @@ set_registers_args0(
16711684 AvailGP ,
16721685 StackOffset
16731686) when is_integer (Value ) ->
1674- LowPartUnsigned = Value band 16#FFFFFFFF ,
1675- HighPartUnsigned = (Value bsr 32 ) band 16#FFFFFFFF ,
1676- % Convert to signed 32-bit values for RISC-V li instruction
1677- LowPart =
1678- if
1679- LowPartUnsigned > 16#7FFFFFFF -> LowPartUnsigned - 16#100000000 ;
1680- true -> LowPartUnsigned
1681- end ,
1682- HighPart =
1683- if
1684- HighPartUnsigned > 16#7FFFFFFF -> HighPartUnsigned - 16#100000000 ;
1685- true -> HighPartUnsigned
1686- end ,
1687+ LowPart = Value band 16#FFFFFFFF ,
1688+ HighPart = (Value bsr 32 ) band 16#FFFFFFFF ,
16871689 set_registers_args0 (
16881690 State , [LowPart , HighPart | ArgsT ], [imm | ArgsRegs ], ParamRegs , AvailGP , StackOffset
16891691 );
@@ -2356,8 +2358,9 @@ set_continuation_to_label(
23562358 % resolved to point directly to the label's actual address (not the jump table entry)
23572359 Offset = StreamModule :offset (Stream0 ),
23582360 % Emit placeholder for pc_relative_address (auipc + addi)
2361+ % Reserve 8 bytes (2 x 32-bit instructions) with all-1s placeholder for flash programming
23592362 % The relocation will replace these with the correct offset
2360- I1 = pc_relative_address ( Temp , 4 ) ,
2363+ I1 = << 16#FFFFFFFF : 32 / little , 16#FFFFFFFF : 32 / little >> ,
23612364 Reloc = {Label , Offset , {adr , Temp }},
23622365 % Store continuation (jit_state is in a1)
23632366 I2 = jit_riscv32_asm :sw (? JITSTATE_REG , Temp , ? JITSTATE_CONTINUATION_OFFSET ),
@@ -2379,7 +2382,8 @@ set_continuation_to_offset(
23792382) ->
23802383 OffsetRef = make_ref (),
23812384 Offset = StreamModule :offset (Stream0 ),
2382- I1 = pc_relative_address (Temp , 4 ),
2385+ % Reserve 8 bytes with all-1s placeholder for flash programming
2386+ I1 = <<16#FFFFFFFF :32 /little , 16#FFFFFFFF :32 /little >>,
23832387 Reloc = {OffsetRef , Offset , {adr , Temp }},
23842388 % Store continuation (jit_state is in a1)
23852389 I2 = jit_riscv32_asm :sw (? JITSTATE_REG , Temp , ? JITSTATE_CONTINUATION_OFFSET ),
@@ -2659,8 +2663,11 @@ decrement_reductions_and_maybe_schedule_next(
26592663 NewI5 =
26602664 case pc_relative_address (Temp , NewI5Offset ) of
26612665 I when byte_size (I ) =:= 4 ->
2662- % Only auipc, pad with NOP
2666+ % Only auipc, pad with NOP (4 bytes)
26632667 <<I /binary , (jit_riscv32_asm :nop ())/binary >>;
2668+ I when byte_size (I ) =:= 6 ->
2669+ % auipc + c.addi, pad with c.nop (2 bytes)
2670+ <<I /binary , (jit_riscv32_asm :c_nop ())/binary >>;
26642671 I when byte_size (I ) =:= 8 ->
26652672 % auipc + addi, no padding needed
26662673 I
@@ -2798,11 +2805,18 @@ rewrite_cp_offset(
27982805 CPValue = NewOffset bsl 2 ,
27992806 NewMoveInstr = jit_riscv32_asm :li (TempReg , CPValue ),
28002807 % We reserved 8 bytes (2 instructions) for the CP value
2801- % If li generates only 4 bytes, pad with a NOP to maintain alignment
2808+ % Pad with NOP if needed to maintain alignment
28022809 PaddedInstr =
28032810 case byte_size (NewMoveInstr ) of
2804- 4 -> <<NewMoveInstr /binary , (jit_riscv32_asm :nop ())/binary >>;
2805- 8 -> NewMoveInstr
2811+ 2 ->
2812+ <<NewMoveInstr /binary , (jit_riscv32_asm :nop ())/binary ,
2813+ (jit_riscv32_asm :c_nop ())/binary >>;
2814+ 4 ->
2815+ <<NewMoveInstr /binary , (jit_riscv32_asm :nop ())/binary >>;
2816+ 6 ->
2817+ <<NewMoveInstr /binary , (jit_riscv32_asm :c_nop ())/binary >>;
2818+ 8 ->
2819+ NewMoveInstr
28062820 end ,
28072821 Stream1 = StreamModule :replace (Stream0 , RewriteOffset , PaddedInstr ),
28082822 State0 # state {stream = Stream1 }.
@@ -2841,13 +2855,22 @@ return_labels_and_lines(
28412855 || {Label , LabelOffset } <- Labels , is_integer (Label )
28422856 ]),
28432857
2844- I1 = pc_relative_address (a0 , 12 ),
28452858 I2 = jit_riscv32_asm :ret (),
2859+ % Assume total size is 10 bytes (8-byte I1 + 2-byte c.ret)
2860+ % If actual is 8 bytes (6-byte I1 + 2-byte c.ret), we'll pad with 2 bytes
2861+ I1 = pc_relative_address (a0 , 10 ),
2862+ Prologue = <<I1 /binary , I2 /binary >>,
2863+ ProloguePadded =
2864+ case byte_size (Prologue ) of
2865+ 10 -> Prologue ;
2866+ % 2-byte padding
2867+ 8 -> <<Prologue /binary , 16#FFFF :16 >>
2868+ end ,
28462869 LabelsTable = <<<<Label :16 , Offset :32 >> || {Label , Offset } <- SortedLabels >>,
28472870 LinesTable = <<<<Line :16 , Offset :32 >> || {Line , Offset } <- SortedLines >>,
28482871 Stream1 = StreamModule :append (
28492872 Stream0 ,
2850- <<I1 / binary , I2 /binary , (length (SortedLabels )):16 , LabelsTable /binary ,
2873+ <<ProloguePadded /binary , (length (SortedLabels )):16 , LabelsTable /binary ,
28512874 (length (SortedLines )):16 , LinesTable /binary >>
28522875 ),
28532876 State # state {stream = Stream1 }.
@@ -3005,7 +3028,7 @@ args_regs(Args) ->
30053028 ).
30063029
30073030% %-----------------------------------------------------------------------------
3008- % % @doc Add a label at the current offset. Eventually align it with a nop.
3031+ % % @doc Add a label at the current offset.
30093032% % @end
30103033% % @param State current backend state
30113034% % @param Label the label number or reference
@@ -3014,15 +3037,7 @@ args_regs(Args) ->
30143037- spec add_label (state (), integer () | reference ()) -> state ().
30153038add_label (# state {stream_module = StreamModule , stream = Stream0 } = State0 , Label ) ->
30163039 Offset0 = StreamModule :offset (Stream0 ),
3017- {State1 , Offset1 } =
3018- if
3019- Offset0 rem 4 =:= 0 ->
3020- {State0 , Offset0 };
3021- true ->
3022- Stream1 = StreamModule :append (Stream0 , jit_riscv32_asm :nop ()),
3023- {State0 # state {stream = Stream1 }, Offset0 + 2 }
3024- end ,
3025- add_label (State1 , Label , Offset1 ).
3040+ add_label (State0 , Label , Offset0 ).
30263041
30273042% %-----------------------------------------------------------------------------
30283043% % @doc Add a label at a specific offset
0 commit comments