Skip to content

Commit 3b3abf4

Browse files
committed
AArch64: increase coverage and use cbz/tbz/tbnz
Signed-off-by: Paul Guyot <[email protected]>
1 parent eb582ff commit 3b3abf4

File tree

4 files changed

+811
-91
lines changed

4 files changed

+811
-91
lines changed

libs/jit/src/jit_aarch64.erl

Lines changed: 47 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,19 @@ if_block(
567567
OffsetAfter = StreamModule:offset(Stream2),
568568
%% Patch the conditional branch instruction to jump to the end of the block
569569
BranchOffset = OffsetAfter - (Offset + BranchInstrOffset),
570-
NewBranchInstr = jit_aarch64_asm:bcc(CC, BranchOffset),
570+
NewBranchInstr =
571+
case CC of
572+
{cbz, Reg} ->
573+
jit_aarch64_asm:cbz(Reg, BranchOffset);
574+
{cbz_w, Reg} ->
575+
jit_aarch64_asm:cbz_w(Reg, BranchOffset);
576+
{tbz, Reg, Bit} ->
577+
jit_aarch64_asm:tbz(Reg, Bit, BranchOffset);
578+
{tbnz, Reg, Bit} ->
579+
jit_aarch64_asm:tbnz(Reg, Bit, BranchOffset);
580+
CC when is_atom(CC) ->
581+
jit_aarch64_asm:bcc(CC, BranchOffset)
582+
end,
571583
Stream3 = StreamModule:replace(Stream2, Offset + BranchInstrOffset, NewBranchInstr),
572584
merge_used_regs(State2#state{stream = Stream3}, State1#state.used_regs).
573585

@@ -621,16 +633,10 @@ if_else_block(
621633

622634
-spec if_block_cond(state(), condition()) -> {state(), jit_aarch64_asm:cc(), non_neg_integer()}.
623635
if_block_cond(#state{stream_module = StreamModule, stream = Stream0} = State0, {Reg, '<', 0}) ->
624-
I1 = jit_aarch64_asm:tst(Reg, Reg),
625-
% pl = positive or zero (>=0)
626-
I2 = jit_aarch64_asm:bcc(pl, 0),
627-
Code = <<
628-
I1/binary,
629-
I2/binary
630-
>>,
631-
Stream1 = StreamModule:append(Stream0, Code),
636+
I = jit_aarch64_asm:tbz(Reg, 63, 0),
637+
Stream1 = StreamModule:append(Stream0, I),
632638
State1 = State0#state{stream = Stream1},
633-
{State1, pl, byte_size(I1)};
639+
{State1, {tbz, Reg, 63}, 0};
634640
if_block_cond(
635641
#state{stream_module = StreamModule, stream = Stream0} = State0,
636642
{RegA, '<', RegB}
@@ -653,17 +659,11 @@ if_block_cond(
653659
{free, Reg0} -> Reg0;
654660
RegOrTuple -> RegOrTuple
655661
end,
656-
I1 = jit_aarch64_asm:tst(Reg, Reg),
657-
% ne = not equal
658-
I2 = jit_aarch64_asm:bcc(ne, 0),
659-
Code = <<
660-
I1/binary,
661-
I2/binary
662-
>>,
663-
Stream1 = StreamModule:append(Stream0, Code),
662+
I = jit_aarch64_asm:cbz(Reg, 0),
663+
Stream1 = StreamModule:append(Stream0, I),
664664
State1 = if_block_free_reg(RegOrTuple, State0),
665665
State2 = State1#state{stream = Stream1},
666-
{State2, ne, byte_size(I1)};
666+
{State2, {cbz, Reg}, 0};
667667
if_block_cond(
668668
#state{stream_module = StreamModule, stream = Stream0} = State0, {'(int)', RegOrTuple, '==', 0}
669669
) ->
@@ -672,16 +672,11 @@ if_block_cond(
672672
{free, Reg0} -> Reg0;
673673
RegOrTuple -> RegOrTuple
674674
end,
675-
I1 = jit_aarch64_asm:tst_w(Reg, Reg),
676-
I2 = jit_aarch64_asm:bcc(ne, 0),
677-
Code = <<
678-
I1/binary,
679-
I2/binary
680-
>>,
681-
Stream1 = StreamModule:append(Stream0, Code),
675+
I = jit_aarch64_asm:cbz_w(Reg, 0),
676+
Stream1 = StreamModule:append(Stream0, I),
682677
State1 = if_block_free_reg(RegOrTuple, State0),
683678
State2 = State1#state{stream = Stream1},
684-
{State2, ne, byte_size(I1)};
679+
{State2, {cbz_w, Reg}, 0};
685680
if_block_cond(
686681
#state{stream_module = StreamModule, stream = Stream0} = State0,
687682
{RegOrTuple, '!=', Val}
@@ -783,17 +778,12 @@ if_block_cond(
783778
{free, Reg0} -> Reg0;
784779
RegOrTuple -> RegOrTuple
785780
end,
786-
% Test low 8 bits
787-
I1 = jit_aarch64_asm:tst_w(Reg, 16#FF),
788-
I2 = jit_aarch64_asm:bcc(ne, 0),
789-
Code = <<
790-
I1/binary,
791-
I2/binary
792-
>>,
793-
Stream1 = StreamModule:append(Stream0, Code),
781+
% Test lowest bit
782+
I = jit_aarch64_asm:tbnz(Reg, 0, 0),
783+
Stream1 = StreamModule:append(Stream0, I),
794784
State1 = if_block_free_reg(RegOrTuple, State0),
795785
State2 = State1#state{stream = Stream1},
796-
{State2, ne, byte_size(I1)};
786+
{State2, {tbnz, Reg, 0}, 0};
797787
if_block_cond(
798788
#state{stream_module = StreamModule, stream = Stream0} = State0,
799789
{'(bool)', RegOrTuple, '!=', false}
@@ -803,8 +793,26 @@ if_block_cond(
803793
{free, Reg0} -> Reg0;
804794
RegOrTuple -> RegOrTuple
805795
end,
806-
% Test low 8 bits
807-
I1 = jit_aarch64_asm:tst_w(Reg, 16#FF),
796+
% Test lowest bit
797+
I = jit_aarch64_asm:tbz(Reg, 0, 0),
798+
Stream1 = StreamModule:append(Stream0, I),
799+
State1 = if_block_free_reg(RegOrTuple, State0),
800+
State2 = State1#state{stream = Stream1},
801+
{State2, {tbz, Reg, 0}, 0};
802+
if_block_cond(
803+
#state{
804+
stream_module = StreamModule,
805+
stream = Stream0
806+
} = State0,
807+
{RegOrTuple, '&', Val, '!=', 0}
808+
) ->
809+
Reg =
810+
case RegOrTuple of
811+
{free, Reg0} -> Reg0;
812+
RegOrTuple -> RegOrTuple
813+
end,
814+
% Test bits
815+
I1 = jit_aarch64_asm:tst(Reg, Val),
808816
I2 = jit_aarch64_asm:bcc(eq, 0),
809817
Code = <<
810818
I1/binary,
@@ -853,53 +861,7 @@ if_block_cond(
853861
Stream3 = StreamModule:append(Stream2, I3),
854862
State3 = State1#state{stream = Stream3},
855863
State4 = if_block_free_reg(RegTuple, State3),
856-
{State4, eq, OffsetAfter - OffsetBefore};
857-
if_block_cond(
858-
#state{
859-
stream_module = StreamModule,
860-
stream = Stream0
861-
} = State0,
862-
{RegOrTuple, '&', Val}
863-
) ->
864-
Reg =
865-
case RegOrTuple of
866-
{free, Reg0} -> Reg0;
867-
RegOrTuple -> RegOrTuple
868-
end,
869-
% Test bits
870-
I1 = jit_aarch64_asm:tst(Reg, Val),
871-
I2 = jit_aarch64_asm:bcc(eq, 0),
872-
Code = <<
873-
I1/binary,
874-
I2/binary
875-
>>,
876-
Stream1 = StreamModule:append(Stream0, Code),
877-
State1 = if_block_free_reg(RegOrTuple, State0),
878-
State2 = State1#state{stream = Stream1},
879-
{State2, eq, byte_size(I1)};
880-
if_block_cond(
881-
#state{
882-
stream_module = StreamModule,
883-
stream = Stream0
884-
} = State0,
885-
{'(bool)', RegOrTuple, '&', Val}
886-
) ->
887-
Reg =
888-
case RegOrTuple of
889-
{free, Reg0} -> Reg0;
890-
RegOrTuple -> RegOrTuple
891-
end,
892-
% Test 8-bit value
893-
I1 = jit_aarch64_asm:tst_w(Reg, Val),
894-
I2 = jit_aarch64_asm:bcc(eq, 0),
895-
Code = <<
896-
I1/binary,
897-
I2/binary
898-
>>,
899-
Stream1 = StreamModule:append(Stream0, Code),
900-
State1 = if_block_free_reg(RegOrTuple, State0),
901-
State2 = State1#state{stream = Stream1},
902-
{State2, eq, byte_size(I1)}.
864+
{State4, eq, OffsetAfter - OffsetBefore}.
903865

904866
-spec if_block_free_reg(aarch64_register() | {free, aarch64_register()}, state()) -> state().
905867
if_block_free_reg({free, Reg}, State0) ->

libs/jit/src/jit_aarch64_asm.erl

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@
3030
blr/1,
3131
br/1,
3232
brk/1,
33+
cbz/2,
34+
cbz_w/2,
35+
tbz/3,
36+
tbnz/3,
3337
cmp/2,
3438
cmp32/2,
3539
and_/3,
@@ -779,6 +783,39 @@ bcc(Cond, Offset) when is_atom(Cond), is_integer(Offset) ->
779783
Offset19 = Offset div 4,
780784
<<(16#54000000 bor ((Offset19 band 16#7FFFF) bsl 5) bor CondNum):32/little>>.
781785

786+
%% Emit a compare and branch on zero
787+
-spec cbz(aarch64_gpr_register(), integer()) -> binary().
788+
cbz(Rt, Offset) when is_integer(Offset) ->
789+
RtNum = reg_to_num(Rt),
790+
Offset19 = Offset div 4,
791+
<<(16#B4000000 bor ((Offset19 band 16#7FFFF) bsl 5) bor RtNum):32/little>>.
792+
793+
-spec cbz_w(aarch64_gpr_register(), integer()) -> binary().
794+
cbz_w(Rt, Offset) when is_integer(Offset) ->
795+
RtNum = reg_to_num(Rt),
796+
Offset19 = Offset div 4,
797+
<<(16#34000000 bor ((Offset19 band 16#7FFFF) bsl 5) bor RtNum):32/little>>.
798+
799+
%% Emit a test bit and branch if zero
800+
-spec tbz(aarch64_gpr_register(), 0..63, integer()) -> binary().
801+
tbz(Rt, Bit, Offset) when Offset >= -32768 andalso Offset < 32768 ->
802+
RtNum = reg_to_num(Rt),
803+
Offset14 = Offset div 4,
804+
<<
805+
((Bit band 32 bsl 26) bor 16#36000000 bor (Bit band 31 bsl 19) bor
806+
((Offset14 band 16#3FFF) bsl 5) bor RtNum):32/little
807+
>>.
808+
809+
%% Emit a test bit and branch if not zero
810+
-spec tbnz(aarch64_gpr_register(), 0..63, integer()) -> binary().
811+
tbnz(Rt, Bit, Offset) when Offset >= -32768 andalso Offset < 32768 ->
812+
RtNum = reg_to_num(Rt),
813+
Offset14 = Offset div 4,
814+
<<
815+
((Bit band 32 bsl 26) bor 16#37000000 bor (Bit band 31 bsl 19) bor
816+
((Offset14 band 16#3FFF) bsl 5) bor RtNum):32/little
817+
>>.
818+
782819
%% Emit a compare instruction
783820
-spec cmp(aarch64_gpr_register(), aarch64_gpr_register() | integer()) -> binary().
784821
cmp(Rn, Rm) when is_atom(Rn), is_atom(Rm) ->

tests/libs/jit/jit_aarch64_asm_tests.erl

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,54 @@ bcc_test_() ->
389389
)
390390
].
391391

392+
cbz_test_() ->
393+
[
394+
?_assertEqual(
395+
asm(<<16#b4000401:32/little>>, "cbz x1, 128"),
396+
jit_aarch64_asm:cbz(r1, 128)
397+
),
398+
?_assertEqual(
399+
asm(<<16#34000402:32/little>>, "cbz w2, 128"),
400+
jit_aarch64_asm:cbz_w(r2, 128)
401+
),
402+
?_assertEqual(
403+
asm(<<16#b4fffc03:32/little>>, "cbz x3, -128"),
404+
jit_aarch64_asm:cbz(r3, -128)
405+
)
406+
].
407+
408+
tbz_test_() ->
409+
[
410+
?_assertEqual(
411+
asm(<<16#b6f80400:32/little>>, "tbz x0, #63, 128"),
412+
jit_aarch64_asm:tbz(r0, 63, 128)
413+
),
414+
?_assertEqual(
415+
asm(<<16#36180400:32/little>>, "tbz x0, #3, 128"),
416+
jit_aarch64_asm:tbz(r0, 3, 128)
417+
),
418+
?_assertEqual(
419+
asm(<<16#363ffc03:32/little>>, "tbz x3, #7, -128"),
420+
jit_aarch64_asm:tbz(r3, 7, -128)
421+
)
422+
].
423+
424+
tbnz_test_() ->
425+
[
426+
?_assertEqual(
427+
asm(<<16#37000400:32/little>>, "tbnz x0, #0, 128"),
428+
jit_aarch64_asm:tbnz(r0, 0, 128)
429+
),
430+
?_assertEqual(
431+
asm(<<16#37180400:32/little>>, "tbnz x0, #3, 128"),
432+
jit_aarch64_asm:tbnz(r0, 3, 128)
433+
),
434+
?_assertEqual(
435+
asm(<<16#373ffc03:32/little>>, "tbnz x3, #7, -128"),
436+
jit_aarch64_asm:tbnz(r3, 7, -128)
437+
)
438+
].
439+
392440
stp_test_() ->
393441
[
394442
?_assertEqual(

0 commit comments

Comments
 (0)