@@ -666,17 +666,20 @@ first_pass(<<?OP_IS_INTEGER, Rest0/binary>>, MMod, MSt0, State0) ->
666666 {MSt1 , Arg1 , Rest2 } = decode_compact_term (Rest1 , MMod , MSt0 , State0 ),
667667 ? TRACE (" OP_IS_INTEGER ~p , ~p \n " , [Label , Arg1 ]),
668668 MSt2 = verify_is_any_integer ({free , Arg1 }, Label , MMod , MSt1 ),
669- ? ASSERT_ALL_NATIVE_FREE (MSt2 ),
670- first_pass (Rest2 , MMod , MSt2 , State0 );
669+ % % After successful type guard, record the known type
670+ MSt3 = set_type_after_guard (MMod , MSt2 , Arg1 , any_integer ),
671+ ? ASSERT_ALL_NATIVE_FREE (MSt3 ),
672+ first_pass (Rest2 , MMod , MSt3 , State0 );
671673% 46
672674first_pass (<<? OP_IS_FLOAT , Rest0 /binary >>, MMod , MSt0 , State0 ) ->
673675 ? ASSERT_ALL_NATIVE_FREE (MSt0 ),
674676 {Label , Rest1 } = decode_label (Rest0 ),
675677 {MSt1 , Arg1 , Rest2 } = decode_compact_term (Rest1 , MMod , MSt0 , State0 ),
676678 ? TRACE (" OP_IS_FLOAT ~p , ~p \n " , [Label , Arg1 ]),
677679 MSt2 = verify_is_boxed_with_tag (Label , Arg1 , ? TERM_BOXED_FLOAT , MMod , MSt1 ),
678- ? ASSERT_ALL_NATIVE_FREE (MSt2 ),
679- first_pass (Rest2 , MMod , MSt2 , State0 );
680+ MSt3 = set_type_after_guard (MMod , MSt2 , Arg1 , float ),
681+ ? ASSERT_ALL_NATIVE_FREE (MSt3 ),
682+ first_pass (Rest2 , MMod , MSt3 , State0 );
680683% 47
681684first_pass (<<? OP_IS_NUMBER , Rest0 /binary >>, MMod , MSt0 , State0 ) ->
682685 ? ASSERT_ALL_NATIVE_FREE (MSt0 ),
@@ -692,8 +695,9 @@ first_pass(<<?OP_IS_NUMBER, Rest0/binary>>, MMod, MSt0, State0) ->
692695 MMod ,
693696 MSt1
694697 ),
695- ? ASSERT_ALL_NATIVE_FREE (MSt2 ),
696- first_pass (Rest2 , MMod , MSt2 , State0 );
698+ MSt3 = set_type_after_guard (MMod , MSt2 , Arg1 , number ),
699+ ? ASSERT_ALL_NATIVE_FREE (MSt3 ),
700+ first_pass (Rest2 , MMod , MSt3 , State0 );
697701% 48
698702first_pass (<<? OP_IS_ATOM , Rest0 /binary >>, MMod , MSt0 , State0 ) ->
699703 ? ASSERT_ALL_NATIVE_FREE (MSt0 ),
@@ -704,8 +708,9 @@ first_pass(<<?OP_IS_ATOM, Rest0/binary>>, MMod, MSt0, State0) ->
704708 MSt3 = cond_jump_to_label (
705709 {{free , Reg }, '&' , ? TERM_IMMED2_TAG_MASK , '!=' , ? TERM_IMMED2_ATOM }, Label , MMod , MSt2
706710 ),
707- ? ASSERT_ALL_NATIVE_FREE (MSt3 ),
708- first_pass (Rest2 , MMod , MSt3 , State0 );
711+ MSt4 = set_type_after_guard (MMod , MSt3 , Arg1 , atom ),
712+ ? ASSERT_ALL_NATIVE_FREE (MSt4 ),
713+ first_pass (Rest2 , MMod , MSt4 , State0 );
709714% 49
710715first_pass (<<? OP_IS_PID , Rest0 /binary >>, MMod , MSt0 , State0 ) ->
711716 ? ASSERT_ALL_NATIVE_FREE (MSt0 ),
@@ -715,8 +720,9 @@ first_pass(<<?OP_IS_PID, Rest0/binary>>, MMod, MSt0, State0) ->
715720 MSt2 = verify_is_immediate_or_boxed (
716721 {free , Arg1 }, ? TERM_PID_TAG , ? TERM_BOXED_EXTERNAL_PID , Label , MMod , MSt1
717722 ),
718- ? ASSERT_ALL_NATIVE_FREE (MSt2 ),
719- first_pass (Rest2 , MMod , MSt2 , State0 );
723+ MSt3 = set_type_after_guard (MMod , MSt2 , Arg1 , pid ),
724+ ? ASSERT_ALL_NATIVE_FREE (MSt3 ),
725+ first_pass (Rest2 , MMod , MSt3 , State0 );
720726% 50
721727first_pass (<<? OP_IS_REFERENCE , Rest0 /binary >>, MMod , MSt0 , State0 ) ->
722728 ? ASSERT_ALL_NATIVE_FREE (MSt0 ),
@@ -759,8 +765,9 @@ first_pass(<<?OP_IS_NIL, Rest0/binary>>, MMod, MSt0, State0) ->
759765 {MSt2 , Reg } = MMod :move_to_native_register (MSt1 , Arg1 ),
760766 MSt3 = cond_jump_to_label ({Reg , '!=' , ? TERM_NIL }, Label , MMod , MSt2 ),
761767 MSt4 = MMod :free_native_registers (MSt3 , [Reg ]),
762- ? ASSERT_ALL_NATIVE_FREE (MSt4 ),
763- first_pass (Rest2 , MMod , MSt4 , State0 );
768+ MSt5 = set_type_after_guard (MMod , MSt4 , Arg1 , nil ),
769+ ? ASSERT_ALL_NATIVE_FREE (MSt5 ),
770+ first_pass (Rest2 , MMod , MSt5 , State0 );
764771% 53
765772first_pass (<<? OP_IS_BINARY , Rest0 /binary >>, MMod , MSt0 , State0 ) ->
766773 ? ASSERT_ALL_NATIVE_FREE (MSt0 ),
@@ -769,8 +776,9 @@ first_pass(<<?OP_IS_BINARY, Rest0/binary>>, MMod, MSt0, State0) ->
769776 ? TRACE (" OP_IS_BINARY ~p , ~p \n " , [Label , Arg1 ]),
770777 MSt2 = verify_is_binary (Arg1 , Label , MMod , MSt1 ),
771778 MSt3 = MMod :free_native_registers (MSt2 , [Arg1 ]),
772- ? ASSERT_ALL_NATIVE_FREE (MSt3 ),
773- first_pass (Rest2 , MMod , MSt3 , State0 );
779+ MSt4 = set_type_after_guard (MMod , MSt3 , Arg1 , binary ),
780+ ? ASSERT_ALL_NATIVE_FREE (MSt4 ),
781+ first_pass (Rest2 , MMod , MSt4 , State0 );
774782% 55
775783first_pass (<<? OP_IS_LIST , Rest0 /binary >>, MMod , MSt0 , State0 ) ->
776784 ? ASSERT_ALL_NATIVE_FREE (MSt0 ),
@@ -787,8 +795,9 @@ first_pass(<<?OP_IS_LIST, Rest0/binary>>, MMod, MSt0, State0) ->
787795 MMod ,
788796 MSt2
789797 ),
790- ? ASSERT_ALL_NATIVE_FREE (MSt3 ),
791- first_pass (Rest2 , MMod , MSt3 , State0 );
798+ MSt4 = set_type_after_guard (MMod , MSt3 , Arg1 , list ),
799+ ? ASSERT_ALL_NATIVE_FREE (MSt4 ),
800+ first_pass (Rest2 , MMod , MSt4 , State0 );
792801% 56
793802first_pass (<<? OP_IS_NONEMPTY_LIST , Rest0 /binary >>, MMod , MSt0 , State0 ) ->
794803 ? ASSERT_ALL_NATIVE_FREE (MSt0 ),
@@ -799,17 +808,19 @@ first_pass(<<?OP_IS_NONEMPTY_LIST, Rest0/binary>>, MMod, MSt0, State0) ->
799808 MSt3 = cond_jump_to_label (
800809 {{free , Reg }, '&' , ? TERM_PRIMARY_MASK , '!=' , ? TERM_PRIMARY_LIST }, Label , MMod , MSt2
801810 ),
802- ? ASSERT_ALL_NATIVE_FREE (MSt3 ),
803- first_pass (Rest2 , MMod , MSt3 , State0 );
811+ MSt4 = set_type_after_guard (MMod , MSt3 , Arg1 , nonempty_list ),
812+ ? ASSERT_ALL_NATIVE_FREE (MSt4 ),
813+ first_pass (Rest2 , MMod , MSt4 , State0 );
804814% 57
805815first_pass (<<? OP_IS_TUPLE , Rest0 /binary >>, MMod , MSt0 , State0 ) ->
806816 ? ASSERT_ALL_NATIVE_FREE (MSt0 ),
807817 {Label , Rest1 } = decode_label (Rest0 ),
808818 {MSt1 , Arg1 , Rest2 } = decode_compact_term (Rest1 , MMod , MSt0 , State0 ),
809819 ? TRACE (" OP_IS_TUPLE ~p , ~p \n " , [Label , Arg1 ]),
810820 MSt2 = verify_is_boxed_with_tag (Label , Arg1 , ? TERM_BOXED_TUPLE , MMod , MSt1 ),
811- ? ASSERT_ALL_NATIVE_FREE (MSt2 ),
812- first_pass (Rest2 , MMod , MSt2 , State0 );
821+ MSt3 = set_type_after_guard (MMod , MSt2 , Arg1 , tuple ),
822+ ? ASSERT_ALL_NATIVE_FREE (MSt3 ),
823+ first_pass (Rest2 , MMod , MSt3 , State0 );
813824% 58
814825first_pass (<<? OP_TEST_ARITY , Rest0 /binary >>, MMod , MSt0 , State0 ) ->
815826 ? ASSERT_ALL_NATIVE_FREE (MSt0 ),
@@ -3391,6 +3402,16 @@ op_gc_bif2_sub(MMod, MSt0, FailLabel, Live, Bif, Arg1, Arg2, Dest, Range1, Range
33913402unwrap_typed ({typed , Arg , _Type }) -> Arg ;
33923403unwrap_typed (Arg ) -> Arg .
33933404
3405+ % % @doc Record type information for a VM register after a successful type guard.
3406+ % % Only records type for x_reg and y_reg sources (not intermediates or immediates).
3407+ set_type_after_guard (MMod , MSt , {x_reg , X }, Type ) when is_integer (X ) ->
3408+ MMod :set_type_tracking (MSt , {x_reg , X }, Type );
3409+ set_type_after_guard (MMod , MSt , {y_reg , Y }, Type ) ->
3410+ MMod :set_type_tracking (MSt , {y_reg , Y }, Type );
3411+ set_type_after_guard (_MMod , MSt , _Arg , _Type ) ->
3412+ % % Argument is not a VM register (immediate, native reg, etc.) - nothing to track
3413+ MSt .
3414+
33943415% Optimized >= comparison for typed integers
33953416% Test if Arg1 >= Arg2, jump to Label if false (i.e., if Arg1 < Arg2)
33963417op_is_ge (MMod , MSt0 , Label , Arg1 , {typed , Arg2 , {t_integer , _Range }}) when is_integer (Arg1 ) ->
0 commit comments