@@ -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
@@ -601,7 +613,19 @@ if_else_block(
601613 OffsetAfter = StreamModule :offset (Stream3 ),
602614 % % Patch the conditional branch to jump to the else block
603615 ElseBranchOffset = OffsetAfter - (Offset + BranchInstrOffset ),
604- NewBranchInstr = jit_aarch64_asm :bcc (CC , ElseBranchOffset ),
616+ NewBranchInstr =
617+ case CC of
618+ {cbz , Reg } ->
619+ jit_aarch64_asm :cbz (Reg , ElseBranchOffset );
620+ {cbz_w , Reg } ->
621+ jit_aarch64_asm :cbz_w (Reg , ElseBranchOffset );
622+ {tbz , Reg , Bit } ->
623+ jit_aarch64_asm :tbz (Reg , Bit , ElseBranchOffset );
624+ {tbnz , Reg , Bit } ->
625+ jit_aarch64_asm :tbnz (Reg , Bit , ElseBranchOffset );
626+ CC when is_atom (CC ) ->
627+ jit_aarch64_asm :bcc (CC , ElseBranchOffset )
628+ end ,
605629 Stream4 = StreamModule :replace (Stream3 , Offset + BranchInstrOffset , NewBranchInstr ),
606630 % % Build the else block
607631 StateElse = State2 # state {
@@ -621,16 +645,10 @@ if_else_block(
621645
622646-spec if_block_cond (state (), condition ()) -> {state (), jit_aarch64_asm :cc (), non_neg_integer ()}.
623647if_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 ),
648+ I = jit_aarch64_asm :tbz (Reg , 63 , 0 ),
649+ Stream1 = StreamModule :append (Stream0 , I ),
632650 State1 = State0 # state {stream = Stream1 },
633- {State1 , pl , byte_size ( I1 ) };
651+ {State1 , { tbz , Reg , 63 }, 0 };
634652if_block_cond (
635653 # state {stream_module = StreamModule , stream = Stream0 } = State0 ,
636654 {RegA , '<' , RegB }
@@ -653,17 +671,11 @@ if_block_cond(
653671 {free , Reg0 } -> Reg0 ;
654672 RegOrTuple -> RegOrTuple
655673 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 ),
674+ I = jit_aarch64_asm :cbz (Reg , 0 ),
675+ Stream1 = StreamModule :append (Stream0 , I ),
664676 State1 = if_block_free_reg (RegOrTuple , State0 ),
665677 State2 = State1 # state {stream = Stream1 },
666- {State2 , ne , byte_size ( I1 ) };
678+ {State2 , { cbz , Reg }, 0 };
667679if_block_cond (
668680 # state {stream_module = StreamModule , stream = Stream0 } = State0 , {'(int)' , RegOrTuple , '==' , 0 }
669681) ->
@@ -672,16 +684,11 @@ if_block_cond(
672684 {free , Reg0 } -> Reg0 ;
673685 RegOrTuple -> RegOrTuple
674686 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 ),
687+ I = jit_aarch64_asm :cbz_w (Reg , 0 ),
688+ Stream1 = StreamModule :append (Stream0 , I ),
682689 State1 = if_block_free_reg (RegOrTuple , State0 ),
683690 State2 = State1 # state {stream = Stream1 },
684- {State2 , ne , byte_size ( I1 ) };
691+ {State2 , { cbz_w , Reg }, 0 };
685692if_block_cond (
686693 # state {stream_module = StreamModule , stream = Stream0 } = State0 ,
687694 {RegOrTuple , '!=' , Val }
@@ -783,17 +790,12 @@ if_block_cond(
783790 {free , Reg0 } -> Reg0 ;
784791 RegOrTuple -> RegOrTuple
785792 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 ),
793+ % Test lowest bit
794+ I = jit_aarch64_asm :tbnz (Reg , 0 , 0 ),
795+ Stream1 = StreamModule :append (Stream0 , I ),
794796 State1 = if_block_free_reg (RegOrTuple , State0 ),
795797 State2 = State1 # state {stream = Stream1 },
796- {State2 , ne , byte_size ( I1 ) };
798+ {State2 , { tbnz , Reg , 0 }, 0 };
797799if_block_cond (
798800 # state {stream_module = StreamModule , stream = Stream0 } = State0 ,
799801 {'(bool)' , RegOrTuple , '!=' , false }
@@ -803,17 +805,44 @@ if_block_cond(
803805 {free , Reg0 } -> Reg0 ;
804806 RegOrTuple -> RegOrTuple
805807 end ,
806- % Test low 8 bits
807- I1 = jit_aarch64_asm :tst_w (Reg , 16#FF ),
808+ % Test lowest bit
809+ I = jit_aarch64_asm :tbz (Reg , 0 , 0 ),
810+ Stream1 = StreamModule :append (Stream0 , I ),
811+ State1 = if_block_free_reg (RegOrTuple , State0 ),
812+ State2 = State1 # state {stream = Stream1 },
813+ {State2 , {tbz , Reg , 0 }, 0 };
814+ if_block_cond (
815+ # state {
816+ stream_module = StreamModule ,
817+ stream = Stream0 ,
818+ available_regs = [Temp | _ ]
819+ } = State0 ,
820+ {RegOrTuple , '&' , Val , '!=' , 0 }
821+ ) ->
822+ Reg =
823+ case RegOrTuple of
824+ {free , Reg0 } -> Reg0 ;
825+ RegOrTuple -> RegOrTuple
826+ end ,
827+ % Test bits
828+ TestCode =
829+ try
830+ jit_aarch64_asm :tst (Reg , Val )
831+ catch
832+ error :{unencodable_immediate , Val } ->
833+ TestCode0 = jit_aarch64_asm :mov (Temp , Val ),
834+ TestCode1 = jit_aarch64_asm :tst (Reg , Temp ),
835+ <<TestCode0 /binary , TestCode1 /binary >>
836+ end ,
808837 I2 = jit_aarch64_asm :bcc (eq , 0 ),
809838 Code = <<
810- I1 /binary ,
839+ TestCode /binary ,
811840 I2 /binary
812841 >>,
813842 Stream1 = StreamModule :append (Stream0 , Code ),
814843 State1 = if_block_free_reg (RegOrTuple , State0 ),
815844 State2 = State1 # state {stream = Stream1 },
816- {State2 , eq , byte_size (I1 )};
845+ {State2 , eq , byte_size (TestCode )};
817846if_block_cond (
818847 # state {
819848 stream_module = StreamModule ,
@@ -853,53 +882,7 @@ if_block_cond(
853882 Stream3 = StreamModule :append (Stream2 , I3 ),
854883 State3 = State1 # state {stream = Stream3 },
855884 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 )}.
885+ {State4 , eq , OffsetAfter - OffsetBefore }.
903886
904887-spec if_block_free_reg (aarch64_register () | {free , aarch64_register ()}, state ()) -> state ().
905888if_block_free_reg ({free , Reg }, State0 ) ->
0 commit comments