61
61
62
62
#define MAX (a , b ) ((a) > (b) ? (a) : (b))
63
63
64
+ // intn.h and term.h headers are decoupled. We check here that sign enum values are matching.
65
+ _Static_assert (
66
+ (int ) TermPositiveInteger == (int ) IntNPositiveInteger , "term/intn definition mismatch" );
67
+ _Static_assert (
68
+ (int ) TermNegativeInteger == (int ) IntNNegativeInteger , "term/intn definition mismatch" );
69
+
64
70
const struct ExportedFunction * bif_registry_get_handler (AtomString module , AtomString function , int arity )
65
71
{
66
72
char bifname [MAX_BIF_NAME_LEN ];
@@ -695,19 +701,30 @@ static inline void intn_to_term_size(size_t n, size_t *intn_data_size, size_t *r
695
701
size_t bytes = n * sizeof (intn_digit_t );
696
702
size_t rounded = ((bytes + 7 ) >> 3 ) << 3 ;
697
703
* intn_data_size = rounded / sizeof (term );
704
+
705
+ if (* intn_data_size == BOXED_TERMS_REQUIRED_FOR_INT64 ) {
706
+ // we need to distinguish between "small" boxed integers, that are integers
707
+ // up to int64, and bigger integers.
708
+ // The real difference is that "small" boxed integers use 2-complement,
709
+ // real bigints not (and also endianess might differ).
710
+ // So we force real bigints to be > BOXED_TERMS_REQUIRED_FOR_INT64 terms
711
+ * intn_data_size = BOXED_TERMS_REQUIRED_FOR_INT64 + 1 ;
712
+ rounded = * intn_data_size * sizeof (term );
713
+ }
714
+
698
715
* rounded_num_len = rounded / sizeof (intn_digit_t );
699
716
}
700
717
701
718
static term make_bigint (Context * ctx , uint32_t fail_label , uint32_t live ,
702
- const intn_digit_t bigres [], size_t bigres_len )
719
+ const intn_digit_t bigres [], size_t bigres_len , intn_integer_sign_t sign )
703
720
{
704
721
size_t count = intn_count_digits (bigres , bigres_len );
705
722
706
723
if (UNLIKELY (count > INTN_MAX_IN_LEN )) {
707
724
RAISE_ERROR_BIF (fail_label , OVERFLOW_ATOM );
708
725
}
709
726
710
- if (count > INTN_INT64_LEN ) {
727
+ if (! intn_fits_int64 ( bigres , count , sign ) ) {
711
728
size_t intn_data_size ;
712
729
size_t rounded_res_len ;
713
730
intn_to_term_size (count , & intn_data_size , & rounded_res_len );
@@ -718,13 +735,14 @@ static term make_bigint(Context *ctx, uint32_t fail_label, uint32_t live,
718
735
RAISE_ERROR_BIF (fail_label , OUT_OF_MEMORY_ATOM );
719
736
}
720
737
721
- term bigres_term = term_create_uninitialized_intn (intn_data_size , & ctx -> heap );
738
+ term bigres_term = term_create_uninitialized_intn (
739
+ intn_data_size , (term_integer_sign_t ) sign , & ctx -> heap );
722
740
intn_digit_t * dest_buf = (void * ) term_intn_data (bigres_term );
723
- intn_sign_extend (bigres , count , rounded_res_len , dest_buf );
741
+ intn_copy (bigres , count , dest_buf , rounded_res_len );
724
742
725
743
return bigres_term ;
726
744
} else {
727
- int64_t res64 = intn_2_digits_to_int64 (bigres , count );
745
+ int64_t res64 = intn_2_digits_to_int64 (bigres , count , sign );
728
746
#if BOXED_TERMS_REQUIRED_FOR_INT64 > 1
729
747
return make_maybe_boxed_int64 (ctx , fail_label , live , res64 );
730
748
#else
@@ -733,36 +751,41 @@ static term make_bigint(Context *ctx, uint32_t fail_label, uint32_t live,
733
751
}
734
752
}
735
753
736
- static void term_to_bigint (term arg1 , intn_digit_t * tmp_buf1 , intn_digit_t * * b1 , size_t * b1_len )
754
+ static void term_to_bigint (term arg1 , intn_digit_t * tmp_buf1 , intn_digit_t * * b1 , size_t * b1_len ,
755
+ intn_integer_sign_t * b1_sign )
737
756
{
738
757
if (term_is_boxed_integer (arg1 )
739
758
&& (term_boxed_size (arg1 ) > (INTN_INT64_LEN * sizeof (intn_digit_t )) / sizeof (term ))) {
740
759
* b1 = term_intn_data (arg1 );
741
760
* b1_len = term_intn_size (arg1 ) * (sizeof (term ) / sizeof (intn_digit_t ));
761
+ * b1_sign = (intn_integer_sign_t ) term_boxed_integer_sign (arg1 );
742
762
} else {
743
763
avm_int64_t i64 = term_maybe_unbox_int64 (arg1 );
744
- int64_to_intn_2 (i64 , tmp_buf1 );
764
+ int64_to_intn_2 (i64 , tmp_buf1 , b1_sign );
745
765
* b1 = tmp_buf1 ;
746
766
* b1_len = INTN_INT64_LEN ;
747
767
}
748
768
}
749
769
750
770
static void args_to_bigint (term arg1 , term arg2 , intn_digit_t * tmp_buf1 , intn_digit_t * tmp_buf2 ,
751
- intn_digit_t * * b1 , size_t * b1_len , intn_digit_t * * b2 , size_t * b2_len )
771
+ intn_digit_t * * b1 , size_t * b1_len , intn_integer_sign_t * b1_sign , intn_digit_t * * b2 ,
772
+ size_t * b2_len , intn_integer_sign_t * b2_sign )
752
773
{
753
774
// arg1 or arg2 may need to be "upgraded",
754
775
// in that case tmp_buf will hold the "upgraded" version
755
- term_to_bigint (arg1 , tmp_buf1 , b1 , b1_len );
756
- term_to_bigint (arg2 , tmp_buf2 , b2 , b2_len );
776
+ term_to_bigint (arg1 , tmp_buf1 , b1 , b1_len , b1_sign );
777
+ term_to_bigint (arg2 , tmp_buf2 , b2 , b2_len , b2_sign );
757
778
}
758
779
759
780
static term mul_int64_to_bigint (
760
781
Context * ctx , uint32_t fail_label , uint32_t live , int64_t val1 , int64_t val2 )
761
782
{
762
783
size_t mul_out_len = INTN_MUL_OUT_LEN (INTN_INT64_LEN , INTN_INT64_LEN );
763
784
intn_digit_t mul_out [mul_out_len ];
764
- intn_mul_int64 (val1 , val2 , mul_out );
765
- return make_bigint (ctx , fail_label , live , mul_out , mul_out_len );
785
+ intn_integer_sign_t out_sign ;
786
+ intn_mul_int64 (val1 , val2 , mul_out , & out_sign );
787
+
788
+ return make_bigint (ctx , fail_label , live , mul_out , mul_out_len , out_sign );
766
789
}
767
790
768
791
static term mul_maybe_bigint (Context * ctx , uint32_t fail_label , uint32_t live , term arg1 , term arg2 )
@@ -772,19 +795,23 @@ static term mul_maybe_bigint(Context *ctx, uint32_t fail_label, uint32_t live, t
772
795
773
796
intn_digit_t * bn1 ;
774
797
size_t bn1_len ;
798
+ intn_integer_sign_t bn1_sign ;
775
799
intn_digit_t * bn2 ;
776
800
size_t bn2_len ;
777
- args_to_bigint (arg1 , arg2 , tmp_buf1 , tmp_buf2 , & bn1 , & bn1_len , & bn2 , & bn2_len );
801
+ intn_integer_sign_t bn2_sign ;
802
+ args_to_bigint (
803
+ arg1 , arg2 , tmp_buf1 , tmp_buf2 , & bn1 , & bn1_len , & bn1_sign , & bn2 , & bn2_len , & bn2_sign );
778
804
779
805
size_t bigres_len = INTN_MUL_OUT_LEN (bn1_len , bn2_len );
780
806
if (bigres_len > INTN_MAX_RES_LEN ) {
781
807
RAISE_ERROR_BIF (fail_label , OVERFLOW_ATOM );
782
808
}
783
809
784
810
intn_digit_t bigres [INTN_MAX_RES_LEN ];
785
- intn_mulmns (bn1 , bn1_len , bn2 , bn2_len , bigres );
811
+ intn_mulmnu (bn1 , bn1_len , bn2 , bn2_len , bigres );
812
+ intn_integer_sign_t res_sign = intn_muldiv_sign (bn1_sign , bn2_sign );
786
813
787
- return make_bigint (ctx , fail_label , live , bigres , bigres_len );
814
+ return make_bigint (ctx , fail_label , live , bigres , bigres_len , res_sign );
788
815
}
789
816
790
817
static term mul_overflow_helper (
0 commit comments