@@ -637,12 +637,105 @@ TermCompareResult term_compare(term t, term other, TermCompareOpts opts, GlobalC
637
637
}
638
638
639
639
} else if (term_is_any_integer (t ) && term_is_any_integer (other )) {
640
- avm_int64_t t_int = term_maybe_unbox_int64 (t );
641
- avm_int64_t other_int = term_maybe_unbox_int64 (other );
642
- if (t_int == other_int ) {
643
- CMP_POP_AND_CONTINUE ();
640
+ term_integer_sign_t t_sign ;
641
+ size_t t_size ;
642
+ if (term_is_boxed (t )) {
643
+ t_sign = term_boxed_integer_sign (t );
644
+ t_size = term_boxed_size (t );
645
+ } else {
646
+ t_sign = term_integer_sign_from_int (term_to_int (t ));
647
+ t_size = 0 ;
648
+ }
649
+ term_integer_sign_t other_sign ;
650
+ size_t other_size ;
651
+ if (term_is_boxed (other )) {
652
+ other_sign = term_boxed_integer_sign (other );
653
+ other_size = term_boxed_size (other );
654
+ } else {
655
+ other_sign = term_integer_sign_from_int (term_to_int (other ));
656
+ other_size = 0 ;
657
+ }
658
+
659
+ _Static_assert (
660
+ TermPositiveInteger < TermNegativeInteger , "Unexpected sign definition in term.h" );
661
+ if (t_sign < other_sign ) {
662
+ result = TermGreaterThan ;
663
+ break ;
664
+ } else if (t_sign > other_sign ) {
665
+ result = TermLessThan ;
666
+ break ;
667
+ }
668
+
669
+ TermCompareResult more_digits_result ;
670
+ TermCompareResult less_digits_result ;
671
+ if (t_sign == TermPositiveInteger ) {
672
+ more_digits_result = TermGreaterThan ;
673
+ less_digits_result = TermLessThan ;
674
+ } else {
675
+ more_digits_result = TermLessThan ;
676
+ less_digits_result = TermGreaterThan ;
677
+ }
678
+
679
+ if (t_size == other_size ) {
680
+ const term * t_ptr = term_to_const_term_ptr (t );
681
+ const term * other_ptr = term_to_const_term_ptr (other );
682
+ bool equals = true;
683
+ if (t_size == 1 ) {
684
+ if (t_ptr [1 ] != other_ptr [1 ]) {
685
+ result = (t_ptr [1 ] > other_ptr [1 ]) ? TermGreaterThan : TermLessThan ;
686
+ break ;
687
+ }
688
+ #if BOXED_TERMS_REQUIRED_FOR_INT64 == 2
689
+ } else if (t_size == 2 ) {
690
+ avm_int64_t t64 = term_unbox_int64 (t );
691
+ avm_int64_t other64 = term_unbox_int64 (other );
692
+ if (t64 != other64 ) {
693
+ result = (t64 > other64 ) ? TermGreaterThan : TermLessThan ;
694
+ break ;
695
+ }
696
+ #endif
697
+ } else {
698
+ #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
699
+ // on 64-bit big endian systems, term size is 64 bit, so a term
700
+ // contains 2 intn_digit_t
701
+ // however inside a big integer digits are in "little endian" order
702
+ // so comparison cannot be directly done in 64-bit chunks
703
+ intn_digit_t * t_digits = (intn_digit_t * ) t_ptr ;
704
+ intn_digit_t * other_digits = (intn_digit_t * ) other_ptr ;
705
+ size_t digits_per_term = (sizeof (term ) / sizeof (intn_digit_t ));
706
+ size_t digit_count = (1 + t_size ) * digits_per_term ;
707
+ // t_digits[0] ... t_digits[digits_per_term - 1] is the boxed header
708
+ for (size_t i = digit_count - 1 ; i >= digits_per_term ; i -- ) {
709
+ if (t_digits [i ] != other_digits [i ]) {
710
+ result = (t_digits [i ] > other_digits [i ]) ? more_digits_result
711
+ : less_digits_result ;
712
+ equals = false;
713
+ break ;
714
+ }
715
+ }
716
+ #elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
717
+ for (size_t i = t_size ; i >= 1 ; i -- ) {
718
+ if (t_ptr [i ] != other_ptr [i ]) {
719
+ result = (t_ptr [i ] > other_ptr [i ]) ? more_digits_result
720
+ : less_digits_result ;
721
+ equals = false;
722
+ break ;
723
+ }
724
+ }
725
+ #else
726
+ #error "Unsupported endianess"
727
+ #endif
728
+ }
729
+ if (equals ) {
730
+ CMP_POP_AND_CONTINUE ();
731
+ } else {
732
+ break ;
733
+ }
734
+ } else if (t_size > other_size ) {
735
+ result = more_digits_result ;
736
+ break ;
644
737
} else {
645
- result = ( t_int > other_int ) ? TermGreaterThan : TermLessThan ;
738
+ result = less_digits_result ;
646
739
break ;
647
740
}
648
741
0 commit comments