24
24
#include <math.h>
25
25
26
26
#include "atom.h"
27
+ #include "intn.h"
27
28
#include "bitstring.h"
28
29
#include "defaultatoms.h"
29
30
#include "dictionary.h"
@@ -618,6 +619,102 @@ term bif_erlang_sub_2(Context *ctx, uint32_t fail_label, int live, term arg1, te
618
619
}
619
620
}
620
621
622
+ static inline void intn_to_term_size (size_t n , size_t * intn_data_size , size_t * rounded_num_len )
623
+ {
624
+ size_t bytes = n * sizeof (intn_digit_t );
625
+ size_t rounded = ((bytes + 7 ) >> 3 ) << 3 ;
626
+ * intn_data_size = rounded / sizeof (term );
627
+ * rounded_num_len = rounded / sizeof (intn_digit_t );
628
+ }
629
+
630
+ static term make_bigint (Context * ctx , uint32_t fail_label , uint32_t live ,
631
+ const intn_digit_t bigres [], size_t bigres_len )
632
+ {
633
+ size_t count = intn_count_digits (bigres , bigres_len );
634
+
635
+ if (UNLIKELY (count > INTN_MAX_IN_LEN )) {
636
+ RAISE_ERROR_BIF (fail_label , OVERFLOW_ATOM );
637
+ }
638
+
639
+ if (count > INTN_INT64_LEN ) {
640
+ size_t intn_data_size ;
641
+ size_t rounded_res_len ;
642
+ intn_to_term_size (count , & intn_data_size , & rounded_res_len );
643
+
644
+ if (UNLIKELY (
645
+ memory_ensure_free_with_roots (ctx , BOXED_INTN_SIZE (intn_data_size ), live , ctx -> x , MEMORY_CAN_SHRINK )
646
+ != MEMORY_GC_OK )) {
647
+ RAISE_ERROR_BIF (fail_label , OUT_OF_MEMORY_ATOM );
648
+ }
649
+
650
+ term bigres_term = term_create_uninitialized_intn (intn_data_size , & ctx -> heap );
651
+ intn_digit_t * dest_buf = (void * ) term_intn_data (bigres_term );
652
+ intn_sign_extend (bigres , count , rounded_res_len , dest_buf );
653
+
654
+ return bigres_term ;
655
+ } else {
656
+ int64_t res64 = intn_2_digits_to_int64 (bigres , count );
657
+ #if BOXED_TERMS_REQUIRED_FOR_INT64 > 1
658
+ return make_maybe_boxed_int64 (ctx , fail_label , live , res64 );
659
+ #else
660
+ return make_maybe_boxed_int (ctx , fail_label , live , res64 );
661
+ #endif
662
+ }
663
+ }
664
+
665
+ static void term_to_big_int (term arg1 , intn_digit_t * tmp_buf1 , intn_digit_t * * b1 , size_t * b1_len )
666
+ {
667
+ if (term_is_boxed_integer (arg1 )
668
+ && (term_boxed_size (arg1 ) > (INTN_INT64_LEN * sizeof (intn_digit_t )) / sizeof (term ))) {
669
+ * b1 = term_intn_data (arg1 );
670
+ * b1_len = term_intn_size (arg1 ) * (sizeof (term ) / sizeof (intn_digit_t ));
671
+ } else {
672
+ avm_int64_t i64 = term_maybe_unbox_int64 (arg1 );
673
+ int64_to_intn_2 (i64 , tmp_buf1 );
674
+ * b1 = tmp_buf1 ;
675
+ * b1_len = INTN_INT64_LEN ;
676
+ }
677
+ }
678
+
679
+ static void pair_to_big_int (term arg1 , term arg2 , intn_digit_t * tmp_buf1 , intn_digit_t * tmp_buf2 ,
680
+ intn_digit_t * * b1 , size_t * b1_len , intn_digit_t * * b2 , size_t * b2_len )
681
+ {
682
+ term_to_big_int (arg1 , tmp_buf1 , b1 , b1_len );
683
+ term_to_big_int (arg2 , tmp_buf2 , b2 , b2_len );
684
+ }
685
+
686
+ static term mul_int64_to_bigint (
687
+ Context * ctx , uint32_t fail_label , uint32_t live , int64_t val1 , int64_t val2 )
688
+ {
689
+ size_t mul_out_len = INTN_MUL_OUT_LEN (INTN_INT64_LEN , INTN_INT64_LEN );
690
+ intn_digit_t mul_out [mul_out_len ];
691
+ intn_mul_int64 (val1 , val2 , mul_out );
692
+ return make_bigint (ctx , fail_label , live , mul_out , mul_out_len );
693
+ }
694
+
695
+ static term mul_maybe_bigint (
696
+ Context * ctx , uint32_t fail_label , uint32_t live , term arg1 , term arg2 )
697
+ {
698
+ intn_digit_t tmp_buf1 [INTN_INT64_LEN ];
699
+ intn_digit_t tmp_buf2 [INTN_INT64_LEN ];
700
+
701
+ intn_digit_t * bn1 ;
702
+ size_t bn1_len ;
703
+ intn_digit_t * bn2 ;
704
+ size_t bn2_len ;
705
+ pair_to_big_int (arg1 , arg2 , tmp_buf1 , tmp_buf2 , & bn1 , & bn1_len , & bn2 , & bn2_len );
706
+
707
+ size_t bigres_len = INTN_MUL_OUT_LEN (bn1_len , bn2_len );
708
+ if (bigres_len > INTN_MAX_RES_LEN ) {
709
+ RAISE_ERROR_BIF (fail_label , OVERFLOW_ATOM );
710
+ }
711
+
712
+ intn_digit_t bigres [INTN_MAX_RES_LEN ];
713
+ intn_mulmns (bn1 , bn1_len , bn2 , bn2_len , bigres );
714
+
715
+ return make_bigint (ctx , fail_label , live , bigres , bigres_len );
716
+ }
717
+
621
718
static term mul_overflow_helper (Context * ctx , uint32_t fail_label , uint32_t live , term arg1 , term arg2 )
622
719
{
623
720
avm_int_t val1 = term_to_int (arg1 );
@@ -637,7 +734,7 @@ static term mul_overflow_helper(Context *ctx, uint32_t fail_label, uint32_t live
637
734
#endif
638
735
639
736
} else {
640
- RAISE_ERROR_BIF ( fail_label , OVERFLOW_ATOM );
737
+ return mul_int64_to_bigint ( ctx , fail_label , live , val1 , val2 );
641
738
}
642
739
}
643
740
@@ -665,8 +762,7 @@ static term mul_boxed_helper(Context *ctx, uint32_t fail_label, uint32_t live, t
665
762
return make_boxed_int64 (ctx , fail_label , live , res64 );
666
763
667
764
#elif BOXED_TERMS_REQUIRED_FOR_INT64 == 1
668
- TRACE ("overflow: arg1: " AVM_INT64_FMT ", arg2: " AVM_INT64_FMT "\n" , arg1 , arg2 );
669
- RAISE_ERROR_BIF (fail_label , OVERFLOW_ATOM );
765
+ return mul_int64_to_bigint (ctx , fail_label , live , val1 , val2 );
670
766
#else
671
767
#error "Unsupported configuration."
672
768
#endif
@@ -682,16 +778,15 @@ static term mul_boxed_helper(Context *ctx, uint32_t fail_label, uint32_t live, t
682
778
avm_int64_t res ;
683
779
684
780
if (BUILTIN_MUL_OVERFLOW_INT64 (val1 , val2 , & res )) {
685
- TRACE ("overflow: arg1: 0x%lx, arg2: 0x%lx\n" , arg1 , arg2 );
686
- RAISE_ERROR_BIF (fail_label , OVERFLOW_ATOM );
781
+ return mul_int64_to_bigint (ctx , fail_label , live , val1 , val2 );
687
782
}
688
783
689
784
return make_maybe_boxed_int64 (ctx , fail_label , live , res );
690
785
}
691
786
#endif
692
787
693
788
default :
694
- UNREACHABLE ( );
789
+ return mul_maybe_bigint ( ctx , fail_label , live , arg1 , arg2 );
695
790
}
696
791
} else {
697
792
avm_float_t farg1 = term_conv_to_float (arg1 );
0 commit comments