~ubuntu-branches/debian/squeeze/erlang/squeeze

« back to all changes in this revision

Viewing changes to erts/emulator/beam/erl_arith.c

  • Committer: Bazaar Package Importer
  • Author(s): Erlang Packagers, Sergei Golovan
  • Date: 2006-12-03 17:07:44 UTC
  • mfrom: (2.1.11 feisty)
  • Revision ID: james.westby@ubuntu.com-20061203170744-rghjwupacqlzs6kv
Tags: 1:11.b.2-4
[ Sergei Golovan ]
Fixed erlang-base and erlang-base-hipe prerm scripts.

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
 * 
16
16
 *     $Id$
17
17
 */
 
18
 
18
19
/*
19
 
** Arithmetic functions formerly found in beam_emu.c
20
 
** now available as bifs as erl_db_util and db_match_compile needs
21
 
** them.
22
 
*/
 
20
 * Arithmetic functions formerly found in beam_emu.c
 
21
 * now available as bifs as erl_db_util and db_match_compile needs
 
22
 * them.
 
23
 */
23
24
 
24
25
 
25
26
#ifdef HAVE_CONFIG_H
36
37
#include "atom.h"
37
38
 
38
39
#ifndef MAX
39
 
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
 
40
#  define MAX(x, y) (((x) > (y)) ? (x) : (y))
 
41
#endif
 
42
 
 
43
#if defined(HEAP_FRAG_ELIM_TEST)
 
44
# define ArithCheck(x)
 
45
# define ArithAlloc(a, b) HAlloc((a), (b))
40
46
#endif
41
47
 
42
48
static Eterm shift(Process* p, Eterm arg1, Eterm arg2, int right);
43
49
 
 
50
#if defined(HEAP_FRAG_ELIM_TEST)
 
51
static ERTS_INLINE void maybe_shrink(Process* p, Eterm* hp, Eterm res, Uint alloc)
 
52
{
 
53
    Uint actual;
 
54
 
 
55
    if (is_immed(res)) {
 
56
        if (p->heap <= hp && hp < p->htop) {
 
57
            p->htop = hp;
 
58
        } else {
 
59
            erts_arith_shrink(p, hp);
 
60
        }
 
61
    } else if ((actual = bignum_header_arity(*hp)+1) < alloc) {
 
62
        if (p->heap <= hp && hp < p->htop) {
 
63
            p->htop = hp+actual;
 
64
        } else {
 
65
            erts_arith_shrink(p, hp+actual);
 
66
        }
 
67
    }
 
68
}
 
69
#else
 
70
static ERTS_INLINE void maybe_shrink(Process* p, Eterm* hp, Eterm res, Uint alloc)
 
71
{
 
72
    Uint actual;
 
73
 
 
74
    if (is_immed(res)) {
 
75
        erts_arith_shrink(p, hp);
 
76
    } else if ((actual = bignum_header_arity(*hp)+1) < alloc) {
 
77
        erts_arith_shrink(p, hp+actual);
 
78
    }
 
79
}
 
80
#endif
 
81
 
44
82
/*
45
83
 ** Bif interfaces
46
84
 */
47
85
 
48
86
BIF_RETTYPE splus_1(BIF_ALIST_1)
49
87
{
50
 
    BIF_RET(BIF_ARG_1);
 
88
    if (is_number(BIF_ARG_1)) {
 
89
        BIF_RET(BIF_ARG_1);
 
90
    } else {
 
91
        BIF_ERROR(BIF_P, BADARITH);
 
92
    }
51
93
52
94
 
53
95
BIF_RETTYPE splus_2(BIF_ALIST_2)
81
123
        BIF_ERROR(BIF_P, BADARITH);
82
124
    }
83
125
    if (is_both_small(BIF_ARG_1,BIF_ARG_2)){
84
 
        BIF_RET(make_small(signed_val(BIF_ARG_1) / signed_val(BIF_ARG_2)));
 
126
        Sint ires = signed_val(BIF_ARG_1) / signed_val(BIF_ARG_2);
 
127
        if (MY_IS_SSMALL(ires))
 
128
            BIF_RET(make_small(ires));
85
129
    } 
86
130
    BIF_RET(erts_int_div(BIF_P, BIF_ARG_1, BIF_ARG_2));
87
131
137
181
static Eterm
138
182
shift(Process* p, Eterm arg1, Eterm arg2, int right)
139
183
{
140
 
    int i;
141
 
    int ires;
 
184
    Sint i;
 
185
    Sint ires;
142
186
    Eterm tmp_big1[2];
143
187
    Eterm* bigp;
144
 
    
 
188
    Uint need;
 
189
 
145
190
    if (right) {
146
191
        if (is_small(arg2)) {
147
192
            i = -signed_val(arg2);
173
218
                    }
174
219
                    BIF_RET(arg1);
175
220
                } else if (i < SMALL_BITS-1) { /* Left shift */
176
 
                    if ((ires > 0 && ((-1 << ((SMALL_BITS-1)-i)) & ires) == 0) ||
177
 
                        ((-1 << ((SMALL_BITS-1)-i)) & ~ires) == 0) {
 
221
                    if ((ires > 0 && ((~(Uint)0 << ((SMALL_BITS-1)-i)) & ires) == 0) ||
 
222
                        ((~(Uint)0 << ((SMALL_BITS-1)-i)) & ~ires) == 0) {
178
223
                        arg1 = make_small(ires << i);
179
224
                        BIF_RET(arg1);
180
225
                    }
191
236
                    else
192
237
                        ires -= (-i / D_EXP);
193
238
                }
194
 
                bigp = ArithAlloc(p, BIG_NEED_SIZE(ires+1));
195
 
 
 
239
                need = BIG_NEED_SIZE(ires+1);
 
240
                bigp = ArithAlloc(p, need);
196
241
                arg1 = big_lshift(arg1, i, bigp);
197
 
                ArithCheck(p);
 
242
                maybe_shrink(p, bigp, arg1, need);
198
243
                if (is_nil(arg1)) {
199
244
                    BIF_ERROR(p, SYSTEM_LIMIT);
200
245
                }
 
246
                ArithCheck(p);
201
247
                BIF_RET(arg1);
202
248
            } else if (is_big(arg1)) {
203
249
                if (i == 0) {
210
256
    BIF_ERROR(p, BADARITH);
211
257
}
212
258
 
213
 
 
214
 
 
215
 
/*
216
 
** bnot is "inlined" in bif, no other part of
217
 
** the runtime need's it, it's too simple....
218
 
*/
219
 
 
220
259
BIF_RETTYPE bnot_1(BIF_ALIST_1)
221
260
{
222
261
    Eterm ret;
 
262
 
223
263
    if (is_small(BIF_ARG_1)) {
224
264
        ret = make_small(~signed_val(BIF_ARG_1));
225
265
    } else if (is_big(BIF_ARG_1)) {
226
 
        Eterm* bigp = ArithAlloc(BIF_P, 
227
 
                                 BIG_NEED_SIZE(big_size(BIF_ARG_1)+1));
 
266
        Uint need = BIG_NEED_SIZE(big_size(BIF_ARG_1)+1);
 
267
        Eterm* bigp = ArithAlloc(BIF_P, need);
 
268
 
228
269
        ret = big_bnot(BIF_ARG_1, bigp);
 
270
        maybe_shrink(BIF_P, bigp, ret, need);
 
271
        if (is_nil(ret)) {
 
272
            BIF_ERROR(BIF_P, SYSTEM_LIMIT);
 
273
        }
229
274
        ArithCheck(BIF_P);
230
 
        if (is_nil(ret)) {
231
 
            BIF_ERROR(BIF_P,SYSTEM_LIMIT);
232
 
        }
233
275
    } else {
234
 
        BIF_ERROR(BIF_P,BADARITH);
 
276
        BIF_ERROR(BIF_P, BADARITH);
235
277
    }
236
278
    BIF_RET(ret);
237
279
238
280
 
239
281
/*
240
 
** Implementation and interfaces for the rest of the runtime system.
241
 
**
242
 
** NB:
243
 
** The global functions named erts_XXX are used by the beam
244
 
** emulator loop, do NOT fiddle with these without considering
245
 
** that fact, please...
246
 
*/
 
282
 * Implementation and interfaces for the rest of the runtime system.
 
283
 *
 
284
 * Note:
 
285
 * The global functions named erts_XXX are used by the beam
 
286
 * emulator loop, do NOT fiddle with these without considering
 
287
 * that fact, please...
 
288
 */
247
289
Eterm
248
290
erts_mixed_plus(Process* p, Eterm arg1, Eterm arg2)
249
291
{
255
297
    dsize_t sz1, sz2, sz;
256
298
    int need_heap;
257
299
    Eterm* hp;
258
 
    int ires;
 
300
    Sint ires;
259
301
 
260
 
    ERTS_FP_CHECK_INIT();
 
302
    ERTS_FP_CHECK_INIT(p);
261
303
    switch (arg1 & _TAG_PRIMARY_MASK) {
262
304
    case TAG_PRIMARY_IMMED1:
263
305
        switch ((arg1 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) {
331
373
                    need_heap = BIG_NEED_SIZE(sz);
332
374
                    hp = ArithAlloc(p, need_heap);
333
375
                    res = big_plus(arg1, arg2, hp);
334
 
                    ArithCheck(p);
335
376
                    if (is_nil(res)) {
 
377
                        erts_arith_shrink(p, hp);
336
378
                        p->freason = SYSTEM_LIMIT;
337
379
                        return THE_NON_VALUE;
338
380
                    }
 
381
                    maybe_shrink(p, hp, res, need_heap);
 
382
                    ArithCheck(p);
339
383
                    return res;
340
384
                case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE):
341
385
                    if (big_to_double(arg1, &f1.fd) < 0) {
374
418
 
375
419
                do_float:
376
420
                    f1.fd = f1.fd + f2.fd;
377
 
                    ERTS_FP_ERROR(f1.fd, goto badarith);
378
 
                    hp = ArithAlloc(p, 3);
 
421
                    ERTS_FP_ERROR(p, f1.fd, goto badarith);
 
422
                    hp = ArithAlloc(p, FLOAT_SIZE_OBJECT);
379
423
                    res = make_float(hp);
380
424
                    ArithCheck(p);
381
425
                    PUT_DOUBLE(f1, hp);
403
447
    dsize_t sz1, sz2, sz;
404
448
    int need_heap;
405
449
    Eterm* hp;
406
 
    int ires;
 
450
    Sint ires;
407
451
 
408
 
    ERTS_FP_CHECK_INIT();
 
452
    ERTS_FP_CHECK_INIT(p);
409
453
    switch (arg1 & _TAG_PRIMARY_MASK) {
410
454
    case TAG_PRIMARY_IMMED1:
411
455
        switch ((arg1 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) {
468
512
                    need_heap = BIG_NEED_SIZE(sz);
469
513
                    hp = ArithAlloc(p, need_heap);
470
514
                    res = big_minus(arg1, arg2, hp);
471
 
                    ArithCheck(p);
472
515
                    if (is_nil(res)) {
 
516
                        erts_arith_shrink(p, hp);
473
517
                        p->freason = SYSTEM_LIMIT;
474
518
                        return THE_NON_VALUE;
475
519
                    }
 
520
                    maybe_shrink(p, hp, res, need_heap);
 
521
                    ArithCheck(p);
476
522
                    return res;
477
523
                default:
478
524
                    goto badarith;
520
566
 
521
567
                do_float:
522
568
                    f1.fd = f1.fd - f2.fd;
523
 
                    ERTS_FP_ERROR(f1.fd, goto badarith);
524
 
                    hp = ArithAlloc(p, 3);
 
569
                    ERTS_FP_ERROR(p, f1.fd, goto badarith);
 
570
                    hp = ArithAlloc(p, FLOAT_SIZE_OBJECT);
525
571
                    res = make_float(hp);
526
572
                    ArithCheck(p);
527
573
                    PUT_DOUBLE(f1, hp);
550
596
    int need_heap;
551
597
    Eterm* hp;
552
598
 
553
 
    ERTS_FP_CHECK_INIT();
 
599
    ERTS_FP_CHECK_INIT(p);
554
600
    switch (arg1 & _TAG_PRIMARY_MASK) {
555
601
    case TAG_PRIMARY_IMMED1:
556
602
        switch ((arg1 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) {
561
607
                case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE):
562
608
                    if ((arg1 == SMALL_ZERO) || (arg2 == SMALL_ZERO)) {
563
609
                        return(SMALL_ZERO);
564
 
                    }
565
 
                    if (arg1 == SMALL_ONE)
 
610
                    } else if (arg1 == SMALL_ONE) {
566
611
                        return(arg2);
567
 
                    if (arg2 == SMALL_ONE)
 
612
                    } else if (arg2 == SMALL_ONE) {
568
613
                        return(arg1);
569
 
                    arg1 = small_to_big(signed_val(arg1), tmp_big1);
570
 
                    arg2 = small_to_big(signed_val(arg2), tmp_big2);
571
 
                    goto do_big;
 
614
                    } else {
 
615
                        Eterm big_res[3];
 
616
 
 
617
                        /*
 
618
                         * The following code is optimized for the case that
 
619
                         * result is small (which should be the most common case
 
620
                         * in practice).
 
621
                         */
 
622
                        arg1 = small_to_big(signed_val(arg1), tmp_big1);
 
623
                        arg2 = small_to_big(signed_val(arg2), tmp_big2);
 
624
                        res = big_times(arg1, arg2, big_res);
 
625
                        if (is_small(res)) {
 
626
                            return res;
 
627
                        } else {
 
628
                            /*
 
629
                             * The result is a a big number.
 
630
                             * Allocate a heap fragment and copy the result.
 
631
                             * Be careful to allocate exactly what we need
 
632
                             * to not leave any holes.
 
633
                             */
 
634
                            Uint arity;
 
635
                            
 
636
                            ASSERT(is_big(res));
 
637
                            hdr = big_res[0];
 
638
                            arity = bignum_header_arity(hdr);
 
639
                            ASSERT(arity == 1 || arity == 2);
 
640
                            hp = ArithAlloc(p, arity+1);
 
641
                            res = make_big(hp);
 
642
                            *hp++ = hdr;
 
643
                            *hp++ = big_res[1];
 
644
                            if (arity > 1) {
 
645
                                *hp = big_res[2];
 
646
                            }
 
647
                            return res;
 
648
                        }
 
649
                    }
572
650
                default:
573
651
                badarith:
574
652
                    p->freason = BADARITH;
584
662
                    if (arg1 == SMALL_ONE)
585
663
                        return(arg2);
586
664
                    arg1 = small_to_big(signed_val(arg1), tmp_big1);
 
665
                    sz = 2 + big_size(arg2);
587
666
                    goto do_big;
588
667
                case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE):
589
668
                    f1.fd = signed_val(arg1);
610
689
                    if (arg2 == SMALL_ONE)
611
690
                        return(arg1);
612
691
                    arg2 = small_to_big(signed_val(arg2), tmp_big2);
 
692
                    sz = 2 + big_size(arg1);
613
693
                    goto do_big;
614
694
                default:
615
695
                    goto badarith;
619
699
                switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) {
620
700
                case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE):
621
701
                case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE):
622
 
 
623
 
                do_big:
624
702
                    sz1 = big_size(arg1);
625
703
                    sz2 = big_size(arg2);
626
704
                    sz = sz1 + sz2;
 
705
 
 
706
                do_big:
627
707
                    need_heap = BIG_NEED_SIZE(sz);
628
 
                    hp = ArithAlloc(p, need_heap);
 
708
                    hp = ArithAlloc(p, need_heap);
629
709
                    res = big_times(arg1, arg2, hp);
630
 
                    ArithCheck(p);
 
710
 
 
711
                    /*
 
712
                     * Note that the result must be big in this case, since
 
713
                     * at least one operand was big to begin with, and
 
714
                     * the absolute value of the other is > 1.
 
715
                     */
 
716
 
631
717
                    if (is_nil(res)) {
 
718
                        erts_arith_shrink(p, hp);
632
719
                        p->freason = SYSTEM_LIMIT;
633
720
                        return THE_NON_VALUE;
634
721
                    }
 
722
                    maybe_shrink(p, hp, res, need_heap);
 
723
                    ArithCheck(p);
635
724
                    return res;
636
725
                case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE):
637
726
                    if (big_to_double(arg1, &f1.fd) < 0) {
670
759
 
671
760
                do_float:
672
761
                    f1.fd = f1.fd * f2.fd;
673
 
                    ERTS_FP_ERROR(f1.fd, goto badarith);
674
 
                    hp = ArithAlloc(p, 3);
 
762
                    ERTS_FP_ERROR(p, f1.fd, goto badarith);
 
763
                    hp = ArithAlloc(p, FLOAT_SIZE_OBJECT);
675
764
                    res = make_float(hp);
676
765
                    ArithCheck(p);
677
766
                    PUT_DOUBLE(f1, hp);
695
784
    Eterm* hp;
696
785
    Eterm hdr;
697
786
 
698
 
    ERTS_FP_CHECK_INIT();
 
787
    ERTS_FP_CHECK_INIT(p);
699
788
    switch (arg1 & _TAG_PRIMARY_MASK) {
700
789
    case TAG_PRIMARY_IMMED1:
701
790
        switch ((arg1 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) {
797
886
 
798
887
                do_float:
799
888
                    f1.fd = f1.fd / f2.fd;
800
 
                    ERTS_FP_ERROR(f1.fd, goto badarith);
801
 
                    hp = ArithAlloc(p, 3);
 
889
                    ERTS_FP_ERROR(p, f1.fd, goto badarith);
 
890
                    hp = ArithAlloc(p, FLOAT_SIZE_OBJECT);
802
891
                    PUT_DOUBLE(f1, hp);
803
892
                    ArithCheck(p);
804
893
                    return make_float(hp);
817
906
Eterm
818
907
erts_int_div(Process* p, Eterm arg1, Eterm arg2)
819
908
{
 
909
    Eterm tmp_big1[2];
820
910
    Eterm tmp_big2[2];
821
911
    int ires;
822
912
 
823
913
    switch (NUMBER_CODE(arg1, arg2)) {
 
914
    case SMALL_SMALL:
 
915
        /* This case occurs if the most negative fixnum is divided by -1. */
 
916
        ASSERT(arg2 == make_small(-1));
 
917
        arg1 = small_to_big(signed_val(arg1), tmp_big1);
 
918
        /*FALLTHROUGH*/
824
919
    case BIG_SMALL:
825
920
        arg2 = small_to_big(signed_val(arg2), tmp_big2);
826
921
        goto L_big_div;
827
922
    case SMALL_BIG:
828
 
        return SMALL_ZERO;
 
923
        if (arg1 != make_small(MIN_SMALL)) {
 
924
            return SMALL_ZERO;
 
925
        }
 
926
        arg1 = small_to_big(signed_val(arg1), tmp_big1);
 
927
        /*FALLTHROUGH*/
829
928
    case BIG_BIG:
830
929
    L_big_div:
831
930
        ires = big_ucomp(arg1, arg2);
837
936
        } else {
838
937
            Eterm* hp;
839
938
            int i = big_size(arg1);
 
939
            Uint need;
840
940
 
841
941
            ires = big_size(arg2);
842
 
            hp = ArithAlloc(p, BIG_NEED_SIZE(i-ires+1) + BIG_NEED_SIZE(i));
 
942
            need = BIG_NEED_SIZE(i-ires+1) + BIG_NEED_SIZE(i);
 
943
            hp = ArithAlloc(p, need);
843
944
            arg1 = big_div(arg1, arg2, hp);
844
 
            ArithCheck(p);
845
945
            if (is_nil(arg1)) {
 
946
                erts_arith_shrink(p, hp);
846
947
                p->freason = SYSTEM_LIMIT;
847
948
                return THE_NON_VALUE;
848
949
            }
 
950
            maybe_shrink(p, hp, arg1, need);
 
951
            ArithCheck(p);
849
952
        }
850
953
        return arg1;
851
954
    default:
857
960
Eterm
858
961
erts_int_rem(Process* p, Eterm arg1, Eterm arg2)
859
962
{
 
963
    Eterm tmp_big1[2];
860
964
    Eterm tmp_big2[2];
861
965
    int ires;
862
966
 
865
969
        arg2 = small_to_big(signed_val(arg2), tmp_big2);
866
970
        goto L_big_rem;
867
971
    case SMALL_BIG:
868
 
        return arg1;
 
972
        if (arg1 != make_small(MIN_SMALL)) {
 
973
            return arg1;
 
974
        }
 
975
        arg1 = small_to_big(signed_val(arg1), tmp_big1);
 
976
        /*FALLTHROUGH*/
869
977
    case BIG_BIG:
870
978
    L_big_rem:
871
979
        ires = big_ucomp(arg1, arg2);
872
980
        if (ires == 0) {
873
981
            arg1 = SMALL_ZERO;
874
982
        } else if (ires > 0) {
875
 
            Eterm* hp = ArithAlloc(p, BIG_NEED_SIZE(big_size(arg1)));
 
983
            Uint need = BIG_NEED_SIZE(big_size(arg1));
 
984
            Eterm* hp = ArithAlloc(p, need);
 
985
 
876
986
            arg1 = big_rem(arg1, arg2, hp);
877
 
            ArithCheck(p);
878
987
            if (is_nil(arg1)) {
 
988
                erts_arith_shrink(p, hp);
879
989
                p->freason = SYSTEM_LIMIT;
880
990
                return THE_NON_VALUE;
881
991
            }
 
992
            maybe_shrink(p, hp, arg1, need);
 
993
            ArithCheck(p);
882
994
        }
883
995
        return arg1;
884
996
    default:
892
1004
    Eterm tmp_big1[2];
893
1005
    Eterm tmp_big2[2];
894
1006
    Eterm* hp;
895
 
    int ires;
 
1007
    int need;
896
1008
 
897
1009
    switch (NUMBER_CODE(arg1, arg2)) {
898
1010
    case SMALL_BIG:
907
1019
        p->freason = BADARITH;
908
1020
        return THE_NON_VALUE;
909
1021
    }
910
 
    ires = BIG_NEED_SIZE(MAX(big_size(arg1), big_size(arg2)) + 1);
911
 
    hp = ArithAlloc(p, ires);
 
1022
    need = BIG_NEED_SIZE(MAX(big_size(arg1), big_size(arg2)) + 1);
 
1023
    hp = ArithAlloc(p, need);
912
1024
    arg1 = big_band(arg1, arg2, hp);
 
1025
    ASSERT(is_not_nil(arg1));
 
1026
    maybe_shrink(p, hp, arg1, need);
913
1027
    ArithCheck(p);
914
 
    ASSERT(is_not_nil(arg1));
915
1028
    return arg1;
916
1029
}
917
1030
 
920
1033
    Eterm tmp_big1[2];
921
1034
    Eterm tmp_big2[2];
922
1035
    Eterm* hp;
923
 
    int ires;
 
1036
    int need;
924
1037
 
925
1038
    switch (NUMBER_CODE(arg1, arg2)) {
926
1039
    case SMALL_BIG:
935
1048
        p->freason = BADARITH;
936
1049
        return THE_NON_VALUE;
937
1050
    }
938
 
    ires = BIG_NEED_SIZE(MAX(big_size(arg1), big_size(arg2)) + 1);
939
 
    hp = ArithAlloc(p, ires);
 
1051
    need = BIG_NEED_SIZE(MAX(big_size(arg1), big_size(arg2)) + 1);
 
1052
    hp = ArithAlloc(p, need);
940
1053
    arg1 = big_bor(arg1, arg2, hp);
 
1054
    ASSERT(is_not_nil(arg1));
 
1055
    maybe_shrink(p, hp, arg1, need);
941
1056
    ArithCheck(p);
942
 
    ASSERT(is_not_nil(arg1));
943
1057
    return arg1;
944
1058
}
945
1059
 
948
1062
    Eterm tmp_big1[2];
949
1063
    Eterm tmp_big2[2];
950
1064
    Eterm* hp;
951
 
    int ires;
 
1065
    int need;
952
1066
 
953
1067
    switch (NUMBER_CODE(arg1, arg2)) {
954
1068
    case SMALL_BIG:
963
1077
        p->freason = BADARITH;
964
1078
        return THE_NON_VALUE;
965
1079
    }
966
 
    ires = BIG_NEED_SIZE(MAX(big_size(arg1), big_size(arg2)) + 1);
967
 
    hp = ArithAlloc(p, ires);
 
1080
    need = BIG_NEED_SIZE(MAX(big_size(arg1), big_size(arg2)) + 1);
 
1081
    hp = ArithAlloc(p, need);
968
1082
    arg1 = big_bxor(arg1, arg2, hp);
 
1083
    ASSERT(is_not_nil(arg1));
 
1084
    maybe_shrink(p, hp, arg1, need);
969
1085
    ArithCheck(p);
970
 
    ASSERT(is_not_nil(arg1));
971
1086
    return arg1;
972
1087
}
 
1088
 
 
1089
Eterm erts_bnot(Process* p, Eterm arg)
 
1090
{
 
1091
    Eterm ret;
 
1092
 
 
1093
    if (is_big(arg)) {
 
1094
        Uint need = BIG_NEED_SIZE(big_size(arg)+1);
 
1095
        Eterm* bigp = ArithAlloc(p, need);
 
1096
 
 
1097
        ret = big_bnot(arg, bigp);
 
1098
        maybe_shrink(p, bigp, ret, need);
 
1099
        if (is_nil(ret)) {
 
1100
            p->freason = SYSTEM_LIMIT;
 
1101
            return NIL;
 
1102
        }
 
1103
        ArithCheck(p);
 
1104
    } else {
 
1105
        p->freason = BADARITH;
 
1106
        return NIL;
 
1107
    }
 
1108
    return ret;
 
1109
 
1110
 
 
1111
#if defined(HEAP_FRAG_ELIM_TEST)
 
1112
#define ERTS_ARITH_FORCE_GC 0
 
1113
 
 
1114
#define ERTS_NEED_GC(p, need) \
 
1115
  (ERTS_ARITH_FORCE_GC || (HEAP_LIMIT((p)) - HEAP_TOP((p))) <= (need))
 
1116
 
 
1117
static ERTS_INLINE void
 
1118
trim_heap(Process* p, Eterm* hp, Eterm res)
 
1119
{
 
1120
    ASSERT(p->heap <= hp && hp <= p->htop);
 
1121
    if (is_immed(res)) {
 
1122
        p->htop = hp;
 
1123
    } else {
 
1124
        ASSERT(is_big(res));
 
1125
        p->htop = hp + bignum_header_arity(*hp) + 1;
 
1126
    }
 
1127
}
 
1128
 
 
1129
/*
 
1130
 * The following are not allowed to be used here
 
1131
 */
 
1132
#define erts_arith_shrink horrible error
 
1133
#define maybe_shrink horrible error
 
1134
#undef ArithAlloc
 
1135
#undef ArithCheck
 
1136
#define ArithAlloc horrible error
 
1137
#define ArithCheck horrible error
 
1138
 
 
1139
 
 
1140
Eterm
 
1141
erts_gc_mixed_plus(Process* p, Eterm* reg, Uint live)
 
1142
{
 
1143
    Eterm arg1;
 
1144
    Eterm arg2;
 
1145
    Eterm tmp_big1[2];
 
1146
    Eterm tmp_big2[2];
 
1147
    Eterm res;
 
1148
    Eterm hdr;
 
1149
    FloatDef f1, f2;
 
1150
    dsize_t sz1, sz2, sz;
 
1151
    int need_heap;
 
1152
    Eterm* hp;
 
1153
    Sint ires;
 
1154
 
 
1155
    arg1 = reg[live];
 
1156
    arg2 = reg[live+1];
 
1157
    ERTS_FP_CHECK_INIT(p);
 
1158
    switch (arg1 & _TAG_PRIMARY_MASK) {
 
1159
    case TAG_PRIMARY_IMMED1:
 
1160
        switch ((arg1 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) {
 
1161
        case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE):
 
1162
            switch (arg2 & _TAG_PRIMARY_MASK) {
 
1163
            case TAG_PRIMARY_IMMED1:
 
1164
                switch ((arg2 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) {
 
1165
                case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE):
 
1166
                    ires = signed_val(arg1) + signed_val(arg2);
 
1167
                    ASSERT(MY_IS_SSMALL(ires) == IS_SSMALL(ires));
 
1168
                    if (MY_IS_SSMALL(ires)) {
 
1169
                        return make_small(ires);
 
1170
                    } else {
 
1171
                        if (ERTS_NEED_GC(p, 2)) {
 
1172
                            erts_garbage_collect(p, 2, reg, live);
 
1173
                        }
 
1174
                        hp = p->htop;
 
1175
                        p->htop += 2;
 
1176
                        res = small_to_big(ires, hp);
 
1177
                        return res;
 
1178
                    }
 
1179
                default:
 
1180
                badarith:
 
1181
                    p->freason = BADARITH;
 
1182
                    return THE_NON_VALUE;
 
1183
                }
 
1184
            case TAG_PRIMARY_BOXED:
 
1185
                hdr = *boxed_val(arg2);
 
1186
                switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) {
 
1187
                case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE):
 
1188
                case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE):
 
1189
                    if (arg1 == SMALL_ZERO) {
 
1190
                        return arg2;
 
1191
                    }
 
1192
                    arg1 = small_to_big(signed_val(arg1), tmp_big1);
 
1193
                    goto do_big;
 
1194
                case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE):
 
1195
                    f1.fd = signed_val(arg1);
 
1196
                    GET_DOUBLE(arg2, f2);
 
1197
                    goto do_float;
 
1198
                default:
 
1199
                    goto badarith;
 
1200
                }
 
1201
            }
 
1202
        default:
 
1203
            goto badarith;
 
1204
        }
 
1205
    case TAG_PRIMARY_BOXED:
 
1206
        hdr = *boxed_val(arg1);
 
1207
        switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) {
 
1208
        case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE):
 
1209
        case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE):
 
1210
            switch (arg2 & _TAG_PRIMARY_MASK) {
 
1211
            case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE):
 
1212
                switch ((arg2 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) {
 
1213
                case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE):
 
1214
                    if (arg2 == SMALL_ZERO) {
 
1215
                        return arg1;
 
1216
                    }
 
1217
                    arg2 = small_to_big(signed_val(arg2), tmp_big2);
 
1218
                    goto do_big;
 
1219
                default:
 
1220
                    goto badarith;
 
1221
                }
 
1222
            case TAG_PRIMARY_BOXED:
 
1223
                hdr = *boxed_val(arg2);
 
1224
                switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) {
 
1225
                case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE):
 
1226
                case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE):
 
1227
                do_big:
 
1228
                    sz1 = big_size(arg1);
 
1229
                    sz2 = big_size(arg2);
 
1230
                    sz = MAX(sz1, sz2)+1;
 
1231
                    need_heap = BIG_NEED_SIZE(sz);
 
1232
                    if (ERTS_NEED_GC(p, need_heap)) {
 
1233
                        erts_garbage_collect(p, 2, reg, live+2);
 
1234
                        if (arg1 != make_big(tmp_big1)) {
 
1235
                            arg1 = reg[live];
 
1236
                        }
 
1237
                        if (arg2 != make_big(tmp_big2)) {
 
1238
                            arg2 = reg[live+1];
 
1239
                        }
 
1240
                    }
 
1241
                    hp = p->htop;
 
1242
                    p->htop += need_heap;
 
1243
                    res = big_plus(arg1, arg2, hp);
 
1244
                    trim_heap(p, hp, res);
 
1245
                    if (is_nil(res)) {
 
1246
                        p->freason = SYSTEM_LIMIT;
 
1247
                        return THE_NON_VALUE;
 
1248
                    }
 
1249
                    return res;
 
1250
                case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE):
 
1251
                    if (big_to_double(arg1, &f1.fd) < 0) {
 
1252
                        goto badarith;
 
1253
                    }
 
1254
                    GET_DOUBLE(arg2, f2);
 
1255
                    goto do_float;
 
1256
                default:
 
1257
                    goto badarith;
 
1258
                }
 
1259
            }
 
1260
        case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE):
 
1261
            switch (arg2 & _TAG_PRIMARY_MASK) {
 
1262
            case TAG_PRIMARY_IMMED1:
 
1263
                switch ((arg2 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) {
 
1264
                case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE):
 
1265
                    GET_DOUBLE(arg1, f1);
 
1266
                    f2.fd = signed_val(arg2);
 
1267
                    goto do_float;
 
1268
                default:
 
1269
                    goto badarith;
 
1270
                }
 
1271
            case TAG_PRIMARY_BOXED:
 
1272
                hdr = *boxed_val(arg2);
 
1273
                switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) {
 
1274
                case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE):
 
1275
                case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE):
 
1276
                    GET_DOUBLE(arg1, f1);
 
1277
                    if (big_to_double(arg2, &f2.fd) < 0) {
 
1278
                        goto badarith;
 
1279
                    }
 
1280
                    goto do_float;
 
1281
                case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE):
 
1282
                    GET_DOUBLE(arg1, f1);
 
1283
                    GET_DOUBLE(arg2, f2);
 
1284
 
 
1285
                do_float:
 
1286
                    f1.fd = f1.fd + f2.fd;
 
1287
                    ERTS_FP_ERROR(p, f1.fd, goto badarith);
 
1288
                    if (ERTS_NEED_GC(p, FLOAT_SIZE_OBJECT)) {
 
1289
                        erts_garbage_collect(p, FLOAT_SIZE_OBJECT, reg, live);
 
1290
                    }
 
1291
                    hp = p->htop;
 
1292
                    p->htop += FLOAT_SIZE_OBJECT;
 
1293
                    res = make_float(hp);
 
1294
                    PUT_DOUBLE(f1, hp);
 
1295
                    return res;
 
1296
                default:
 
1297
                    goto badarith;
 
1298
                }
 
1299
            default:
 
1300
                goto badarith;
 
1301
            }
 
1302
        }
 
1303
    default:
 
1304
        goto badarith;
 
1305
    }
 
1306
}
 
1307
 
 
1308
Eterm
 
1309
erts_gc_mixed_minus(Process* p, Eterm* reg, Uint live)
 
1310
{
 
1311
    Eterm arg1;
 
1312
    Eterm arg2;
 
1313
    Eterm tmp_big1[2];
 
1314
    Eterm tmp_big2[2];
 
1315
    Eterm hdr;
 
1316
    Eterm res;
 
1317
    FloatDef f1, f2;
 
1318
    dsize_t sz1, sz2, sz;
 
1319
    int need_heap;
 
1320
    Eterm* hp;
 
1321
    Sint ires;
 
1322
 
 
1323
    arg1 = reg[live];
 
1324
    arg2 = reg[live+1];
 
1325
    ERTS_FP_CHECK_INIT(p);
 
1326
    switch (arg1 & _TAG_PRIMARY_MASK) {
 
1327
    case TAG_PRIMARY_IMMED1:
 
1328
        switch ((arg1 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) {
 
1329
        case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE):
 
1330
            switch (arg2 & _TAG_PRIMARY_MASK) {
 
1331
            case TAG_PRIMARY_IMMED1:
 
1332
                switch ((arg2 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) {
 
1333
                case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE):
 
1334
                    ires = signed_val(arg1) - signed_val(arg2);
 
1335
                    ASSERT(MY_IS_SSMALL(ires) == IS_SSMALL(ires));
 
1336
                    if (MY_IS_SSMALL(ires)) {
 
1337
                        return make_small(ires);
 
1338
                    } else {
 
1339
                        if (ERTS_NEED_GC(p, 2)) {
 
1340
                            erts_garbage_collect(p, 2, reg, live);
 
1341
                        }
 
1342
                        hp = p->htop;
 
1343
                        p->htop += 2;
 
1344
                        res = small_to_big(ires, hp);
 
1345
                        return res;
 
1346
                    }
 
1347
                default:
 
1348
                badarith:
 
1349
                    p->freason = BADARITH;
 
1350
                    return THE_NON_VALUE;
 
1351
                }
 
1352
            case TAG_PRIMARY_BOXED:
 
1353
                hdr = *boxed_val(arg2);
 
1354
                switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) {
 
1355
                case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE):
 
1356
                case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE):
 
1357
                    arg1 = small_to_big(signed_val(arg1), tmp_big1);
 
1358
                    goto do_big;
 
1359
                case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE):
 
1360
                    f1.fd = signed_val(arg1);
 
1361
                    GET_DOUBLE(arg2, f2);
 
1362
                    goto do_float;
 
1363
                default:
 
1364
                    goto badarith;
 
1365
                }
 
1366
            }
 
1367
        default:
 
1368
            goto badarith;
 
1369
        }
 
1370
    case TAG_PRIMARY_BOXED:
 
1371
        hdr = *boxed_val(arg1);
 
1372
        switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) {
 
1373
        case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE):
 
1374
        case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE):
 
1375
            switch (arg2 & _TAG_PRIMARY_MASK) {
 
1376
            case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE):
 
1377
                switch ((arg2 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) {
 
1378
                case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE):
 
1379
                    if (arg2 == SMALL_ZERO) {
 
1380
                        return arg1;
 
1381
                    }
 
1382
                    arg2 = small_to_big(signed_val(arg2), tmp_big2);
 
1383
 
 
1384
                do_big:
 
1385
                    sz1 = big_size(arg1);
 
1386
                    sz2 = big_size(arg2);
 
1387
                    sz = MAX(sz1, sz2)+1;
 
1388
                    need_heap = BIG_NEED_SIZE(sz);
 
1389
                    if (ERTS_NEED_GC(p, need_heap)) {
 
1390
                        erts_garbage_collect(p, need_heap, reg, live+2);
 
1391
                        if (arg1 != make_big(tmp_big1)) {
 
1392
                            arg1 = reg[live];
 
1393
                        }
 
1394
                        if (arg2 != make_big(tmp_big2)) {
 
1395
                            arg2 = reg[live+1];
 
1396
                        }
 
1397
                    }
 
1398
                    hp = p->htop;
 
1399
                    p->htop += need_heap;
 
1400
                    res = big_minus(arg1, arg2, hp);
 
1401
                    trim_heap(p, hp, res);
 
1402
                    if (is_nil(res)) {
 
1403
                        p->freason = SYSTEM_LIMIT;
 
1404
                        return THE_NON_VALUE;
 
1405
                    }
 
1406
                    return res;
 
1407
                default:
 
1408
                    goto badarith;
 
1409
                }
 
1410
            case TAG_PRIMARY_BOXED:
 
1411
                hdr = *boxed_val(arg2);
 
1412
                switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) {
 
1413
                case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE):
 
1414
                case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE):
 
1415
                    goto do_big;
 
1416
                case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE):
 
1417
                    if (big_to_double(arg1, &f1.fd) < 0) {
 
1418
                        goto badarith;
 
1419
                    }
 
1420
                    GET_DOUBLE(arg2, f2);
 
1421
                    goto do_float;
 
1422
                default:
 
1423
                    goto badarith;
 
1424
                }
 
1425
            }
 
1426
        case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE):
 
1427
            switch (arg2 & _TAG_PRIMARY_MASK) {
 
1428
            case TAG_PRIMARY_IMMED1:
 
1429
                switch ((arg2 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) {
 
1430
                case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE):
 
1431
                    GET_DOUBLE(arg1, f1);
 
1432
                    f2.fd = signed_val(arg2);
 
1433
                    goto do_float;
 
1434
                default:
 
1435
                    goto badarith;
 
1436
                }
 
1437
            case TAG_PRIMARY_BOXED:
 
1438
                hdr = *boxed_val(arg2);
 
1439
                switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) {
 
1440
                case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE):
 
1441
                case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE):
 
1442
                    GET_DOUBLE(arg1, f1);
 
1443
                    if (big_to_double(arg2, &f2.fd) < 0) {
 
1444
                        goto badarith;
 
1445
                    }
 
1446
                    goto do_float;
 
1447
                case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE):
 
1448
                    GET_DOUBLE(arg1, f1);
 
1449
                    GET_DOUBLE(arg2, f2);
 
1450
 
 
1451
                do_float:
 
1452
                    f1.fd = f1.fd - f2.fd;
 
1453
                    ERTS_FP_ERROR(p, f1.fd, goto badarith);
 
1454
                    if (ERTS_NEED_GC(p, FLOAT_SIZE_OBJECT)) {
 
1455
                        erts_garbage_collect(p, FLOAT_SIZE_OBJECT, reg, live);
 
1456
                    }
 
1457
                    hp = p->htop;
 
1458
                    p->htop += FLOAT_SIZE_OBJECT;
 
1459
                    res = make_float(hp);
 
1460
                    PUT_DOUBLE(f1, hp);
 
1461
                    return res;
 
1462
                default:
 
1463
                    goto badarith;
 
1464
                }
 
1465
            default:
 
1466
                goto badarith;
 
1467
            }
 
1468
        }
 
1469
    default:
 
1470
        goto badarith;
 
1471
    }
 
1472
}
 
1473
 
 
1474
Eterm
 
1475
erts_gc_mixed_times(Process* p, Eterm* reg, Uint live)
 
1476
{
 
1477
    Eterm arg1;
 
1478
    Eterm arg2;
 
1479
    Eterm tmp_big1[2];
 
1480
    Eterm tmp_big2[2];
 
1481
    Eterm hdr;
 
1482
    Eterm res;
 
1483
    FloatDef f1, f2;
 
1484
    dsize_t sz1, sz2, sz;
 
1485
    int need_heap;
 
1486
    Eterm* hp;
 
1487
 
 
1488
    arg1 = reg[live];
 
1489
    arg2 = reg[live+1];
 
1490
    ERTS_FP_CHECK_INIT(p);
 
1491
    switch (arg1 & _TAG_PRIMARY_MASK) {
 
1492
    case TAG_PRIMARY_IMMED1:
 
1493
        switch ((arg1 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) {
 
1494
        case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE):
 
1495
            switch (arg2 & _TAG_PRIMARY_MASK) {
 
1496
            case TAG_PRIMARY_IMMED1:
 
1497
                switch ((arg2 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) {
 
1498
                case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE):
 
1499
                    if ((arg1 == SMALL_ZERO) || (arg2 == SMALL_ZERO)) {
 
1500
                        return(SMALL_ZERO);
 
1501
                    } else if (arg1 == SMALL_ONE) {
 
1502
                        return(arg2);
 
1503
                    } else if (arg2 == SMALL_ONE) {
 
1504
                        return(arg1);
 
1505
                    } else {
 
1506
                        Eterm big_res[3];
 
1507
 
 
1508
                        /*
 
1509
                         * The following code is optimized for the case that
 
1510
                         * result is small (which should be the most common case
 
1511
                         * in practice).
 
1512
                         */
 
1513
                        arg1 = small_to_big(signed_val(arg1), tmp_big1);
 
1514
                        arg2 = small_to_big(signed_val(arg2), tmp_big2);
 
1515
                        res = big_times(arg1, arg2, big_res);
 
1516
                        if (is_small(res)) {
 
1517
                            return res;
 
1518
                        } else {
 
1519
                            /*
 
1520
                             * The result is a a big number.
 
1521
                             * Allocate a heap fragment and copy the result.
 
1522
                             * Be careful to allocate exactly what we need
 
1523
                             * to not leave any holes.
 
1524
                             */
 
1525
                            Uint arity;
 
1526
                            Uint need;
 
1527
                            
 
1528
                            ASSERT(is_big(res));
 
1529
                            hdr = big_res[0];
 
1530
                            arity = bignum_header_arity(hdr);
 
1531
                            ASSERT(arity == 1 || arity == 2);
 
1532
                            need = arity + 1;
 
1533
                            if (ERTS_NEED_GC(p, need)) {
 
1534
                                erts_garbage_collect(p, need, reg, live);
 
1535
                            }
 
1536
                            hp = p->htop;
 
1537
                            p->htop += need;
 
1538
                            res = make_big(hp);
 
1539
                            *hp++ = hdr;
 
1540
                            *hp++ = big_res[1];
 
1541
                            if (arity > 1) {
 
1542
                                *hp = big_res[2];
 
1543
                            }
 
1544
                            return res;
 
1545
                        }
 
1546
                    }
 
1547
                default:
 
1548
                badarith:
 
1549
                    p->freason = BADARITH;
 
1550
                    return THE_NON_VALUE;
 
1551
                }
 
1552
            case TAG_PRIMARY_BOXED:
 
1553
                hdr = *boxed_val(arg2);
 
1554
                switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) {
 
1555
                case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE):
 
1556
                case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE):
 
1557
                    if (arg1 == SMALL_ZERO)
 
1558
                        return(SMALL_ZERO);
 
1559
                    if (arg1 == SMALL_ONE)
 
1560
                        return(arg2);
 
1561
                    arg1 = small_to_big(signed_val(arg1), tmp_big1);
 
1562
                    sz = 2 + big_size(arg2);
 
1563
                    goto do_big;
 
1564
                case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE):
 
1565
                    f1.fd = signed_val(arg1);
 
1566
                    GET_DOUBLE(arg2, f2);
 
1567
                    goto do_float;
 
1568
                default:
 
1569
                    goto badarith;
 
1570
                }
 
1571
            }
 
1572
        default:
 
1573
            goto badarith;
 
1574
        }
 
1575
    case TAG_PRIMARY_BOXED:
 
1576
        hdr = *boxed_val(arg1);
 
1577
        switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) {
 
1578
        case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE):
 
1579
        case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE):
 
1580
            switch (arg2 & _TAG_PRIMARY_MASK) {
 
1581
            case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE):
 
1582
                switch ((arg2 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) {
 
1583
                case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE):
 
1584
                    if (arg2 == SMALL_ZERO)
 
1585
                        return(SMALL_ZERO);
 
1586
                    if (arg2 == SMALL_ONE)
 
1587
                        return(arg1);
 
1588
                    arg2 = small_to_big(signed_val(arg2), tmp_big2);
 
1589
                    sz = 2 + big_size(arg1);
 
1590
                    goto do_big;
 
1591
                default:
 
1592
                    goto badarith;
 
1593
                }
 
1594
            case TAG_PRIMARY_BOXED:
 
1595
                hdr = *boxed_val(arg2);
 
1596
                switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) {
 
1597
                case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE):
 
1598
                case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE):
 
1599
                    sz1 = big_size(arg1);
 
1600
                    sz2 = big_size(arg2);
 
1601
                    sz = sz1 + sz2;
 
1602
 
 
1603
                do_big:
 
1604
                    need_heap = BIG_NEED_SIZE(sz);
 
1605
                    if (ERTS_NEED_GC(p, need_heap)) {
 
1606
                        erts_garbage_collect(p, need_heap, reg, live+2);
 
1607
                        if (arg1 != make_big(tmp_big1)) {
 
1608
                            arg1 = reg[live];
 
1609
                        }
 
1610
                        if (arg2 != make_big(tmp_big2)) {
 
1611
                            arg2 = reg[live+1];
 
1612
                        }
 
1613
                    }
 
1614
                    hp = p->htop;
 
1615
                    p->htop += need_heap;
 
1616
                    res = big_times(arg1, arg2, hp);
 
1617
                    trim_heap(p, hp, res);
 
1618
 
 
1619
                    /*
 
1620
                     * Note that the result must be big in this case, since
 
1621
                     * at least one operand was big to begin with, and
 
1622
                     * the absolute value of the other is > 1.
 
1623
                     */
 
1624
 
 
1625
                    if (is_nil(res)) {
 
1626
                        p->freason = SYSTEM_LIMIT;
 
1627
                        return THE_NON_VALUE;
 
1628
                    }
 
1629
                    return res;
 
1630
                case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE):
 
1631
                    if (big_to_double(arg1, &f1.fd) < 0) {
 
1632
                        goto badarith;
 
1633
                    }
 
1634
                    GET_DOUBLE(arg2, f2);
 
1635
                    goto do_float;
 
1636
                default:
 
1637
                    goto badarith;
 
1638
                }
 
1639
            }
 
1640
        case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE):
 
1641
            switch (arg2 & _TAG_PRIMARY_MASK) {
 
1642
            case TAG_PRIMARY_IMMED1:
 
1643
                switch ((arg2 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) {
 
1644
                case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE):
 
1645
                    GET_DOUBLE(arg1, f1);
 
1646
                    f2.fd = signed_val(arg2);
 
1647
                    goto do_float;
 
1648
                default:
 
1649
                    goto badarith;
 
1650
                }
 
1651
            case TAG_PRIMARY_BOXED:
 
1652
                hdr = *boxed_val(arg2);
 
1653
                switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) {
 
1654
                case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE):
 
1655
                case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE):
 
1656
                    GET_DOUBLE(arg1, f1);
 
1657
                    if (big_to_double(arg2, &f2.fd) < 0) {
 
1658
                        goto badarith;
 
1659
                    }
 
1660
                    goto do_float;
 
1661
                case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE):
 
1662
                    GET_DOUBLE(arg1, f1);
 
1663
                    GET_DOUBLE(arg2, f2);
 
1664
 
 
1665
                do_float:
 
1666
                    f1.fd = f1.fd * f2.fd;
 
1667
                    ERTS_FP_ERROR(p, f1.fd, goto badarith);
 
1668
                    if (ERTS_NEED_GC(p, FLOAT_SIZE_OBJECT)) {
 
1669
                        erts_garbage_collect(p, FLOAT_SIZE_OBJECT, reg, live);
 
1670
                    }
 
1671
                    hp = p->htop;
 
1672
                    p->htop += FLOAT_SIZE_OBJECT;
 
1673
                    res = make_float(hp);
 
1674
                    PUT_DOUBLE(f1, hp);
 
1675
                    return res;
 
1676
                default:
 
1677
                    goto badarith;
 
1678
                }
 
1679
            default:
 
1680
                goto badarith;
 
1681
            }
 
1682
        }
 
1683
    default:
 
1684
        goto badarith;
 
1685
    }
 
1686
}
 
1687
 
 
1688
Eterm
 
1689
erts_gc_mixed_div(Process* p, Eterm* reg, Uint live)
 
1690
{
 
1691
    Eterm arg1;
 
1692
    Eterm arg2;
 
1693
    FloatDef f1, f2;
 
1694
    Eterm* hp;
 
1695
    Eterm hdr;
 
1696
 
 
1697
    arg1 = reg[live];
 
1698
    arg2 = reg[live+1];
 
1699
    ERTS_FP_CHECK_INIT(p);
 
1700
    switch (arg1 & _TAG_PRIMARY_MASK) {
 
1701
    case TAG_PRIMARY_IMMED1:
 
1702
        switch ((arg1 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) {
 
1703
        case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE):
 
1704
            switch (arg2 & _TAG_PRIMARY_MASK) {
 
1705
            case TAG_PRIMARY_IMMED1:
 
1706
                switch ((arg2 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) {
 
1707
                case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE):
 
1708
                    f1.fd = signed_val(arg1);
 
1709
                    f2.fd = signed_val(arg2);
 
1710
                    goto do_float;
 
1711
                default:
 
1712
                badarith:
 
1713
                    p->freason = BADARITH;
 
1714
                    return THE_NON_VALUE;
 
1715
                }
 
1716
            case TAG_PRIMARY_BOXED:
 
1717
                hdr = *boxed_val(arg2);
 
1718
                switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) {
 
1719
                case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE):
 
1720
                case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE):
 
1721
                    f1.fd = signed_val(arg1);
 
1722
                    if (big_to_double(arg2, &f2.fd) < 0) {
 
1723
                        goto badarith;
 
1724
                    }
 
1725
                    goto do_float;
 
1726
                case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE):
 
1727
                    f1.fd = signed_val(arg1);
 
1728
                    GET_DOUBLE(arg2, f2);
 
1729
                    goto do_float;
 
1730
                default:
 
1731
                    goto badarith;
 
1732
                }
 
1733
            }
 
1734
        default:
 
1735
            goto badarith;
 
1736
        }
 
1737
    case TAG_PRIMARY_BOXED:
 
1738
        hdr = *boxed_val(arg1);
 
1739
        switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) {
 
1740
        case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE):
 
1741
        case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE):
 
1742
            switch (arg2 & _TAG_PRIMARY_MASK) {
 
1743
            case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE):
 
1744
                switch ((arg2 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) {
 
1745
                case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE):
 
1746
                    if (big_to_double(arg1, &f1.fd) < 0) {
 
1747
                        goto badarith;
 
1748
                    }
 
1749
                    f2.fd = signed_val(arg2);
 
1750
                    goto do_float;
 
1751
                default:
 
1752
                    goto badarith;
 
1753
                }
 
1754
            case TAG_PRIMARY_BOXED:
 
1755
                hdr = *boxed_val(arg2);
 
1756
                switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) {
 
1757
                case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE):
 
1758
                case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE):
 
1759
                    if (big_to_double(arg1, &f1.fd) < 0 ||
 
1760
                        big_to_double(arg2, &f2.fd) < 0) {
 
1761
                        goto badarith;
 
1762
                    }
 
1763
                    goto do_float;
 
1764
                case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE):
 
1765
                    if (big_to_double(arg1, &f1.fd) < 0) {
 
1766
                        goto badarith;
 
1767
                    }
 
1768
                    GET_DOUBLE(arg2, f2);
 
1769
                    goto do_float;
 
1770
                default:
 
1771
                    goto badarith;
 
1772
                }
 
1773
            }
 
1774
        case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE):
 
1775
            switch (arg2 & _TAG_PRIMARY_MASK) {
 
1776
            case TAG_PRIMARY_IMMED1:
 
1777
                switch ((arg2 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) {
 
1778
                case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE):
 
1779
                    GET_DOUBLE(arg1, f1);
 
1780
                    f2.fd = signed_val(arg2);
 
1781
                    goto do_float;
 
1782
                default:
 
1783
                    goto badarith;
 
1784
                }
 
1785
            case TAG_PRIMARY_BOXED:
 
1786
                hdr = *boxed_val(arg2);
 
1787
                switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) {
 
1788
                case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE):
 
1789
                case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE):
 
1790
                    GET_DOUBLE(arg1, f1);
 
1791
                    if (big_to_double(arg2, &f2.fd) < 0) {
 
1792
                        goto badarith;
 
1793
                    }
 
1794
                    goto do_float;
 
1795
                case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE):
 
1796
                    GET_DOUBLE(arg1, f1);
 
1797
                    GET_DOUBLE(arg2, f2);
 
1798
 
 
1799
                do_float:
 
1800
                    f1.fd = f1.fd / f2.fd;
 
1801
                    ERTS_FP_ERROR(p, f1.fd, goto badarith);
 
1802
                    if (ERTS_NEED_GC(p, FLOAT_SIZE_OBJECT)) {
 
1803
                        erts_garbage_collect(p, FLOAT_SIZE_OBJECT, reg, live);
 
1804
                    }
 
1805
                    hp = p->htop;
 
1806
                    p->htop += FLOAT_SIZE_OBJECT;
 
1807
                    PUT_DOUBLE(f1, hp);
 
1808
                    return make_float(hp);
 
1809
                default:
 
1810
                    goto badarith;
 
1811
                }
 
1812
            default:
 
1813
                goto badarith;
 
1814
            }
 
1815
        }
 
1816
    default:
 
1817
        goto badarith;
 
1818
    }
 
1819
}
 
1820
 
 
1821
Eterm
 
1822
erts_gc_int_div(Process* p, Eterm* reg, Uint live)
 
1823
{
 
1824
    Eterm arg1;
 
1825
    Eterm arg2;
 
1826
    Eterm tmp_big1[2];
 
1827
    Eterm tmp_big2[2];
 
1828
    int ires;
 
1829
 
 
1830
    arg1 = reg[live];
 
1831
    arg2 = reg[live+1];
 
1832
    switch (NUMBER_CODE(arg1, arg2)) {
 
1833
    case SMALL_SMALL:
 
1834
        /* This case occurs if the most negative fixnum is divided by -1. */
 
1835
        ASSERT(arg2 == make_small(-1));
 
1836
        arg1 = small_to_big(signed_val(arg1), tmp_big1);
 
1837
        /*FALLTHROUGH*/
 
1838
    case BIG_SMALL:
 
1839
        arg2 = small_to_big(signed_val(arg2), tmp_big2);
 
1840
        goto L_big_div;
 
1841
    case SMALL_BIG:
 
1842
        if (arg1 != make_small(MIN_SMALL)) {
 
1843
            return SMALL_ZERO;
 
1844
        }
 
1845
        arg1 = small_to_big(signed_val(arg1), tmp_big1);
 
1846
        /*FALLTHROUGH*/
 
1847
    case BIG_BIG:
 
1848
    L_big_div:
 
1849
        ires = big_ucomp(arg1, arg2);
 
1850
        if (ires < 0) {
 
1851
            arg1 = SMALL_ZERO;
 
1852
        } else if (ires == 0) {
 
1853
            arg1 = (big_sign(arg1) == big_sign(arg2)) ?
 
1854
                SMALL_ONE : SMALL_MINUS_ONE;
 
1855
        } else {
 
1856
            Eterm* hp;
 
1857
            int i = big_size(arg1);
 
1858
            Uint need;
 
1859
 
 
1860
            ires = big_size(arg2);
 
1861
            need = BIG_NEED_SIZE(i-ires+1) + BIG_NEED_SIZE(i);
 
1862
            if (ERTS_NEED_GC(p, need)) {
 
1863
                erts_garbage_collect(p, need, reg, live+2);
 
1864
                if (arg1 != make_big(tmp_big1)) {
 
1865
                    arg1 = reg[live];
 
1866
                }
 
1867
                if (arg2 != make_big(tmp_big2)) {
 
1868
                    arg2 = reg[live+1];
 
1869
                }
 
1870
            }
 
1871
            hp = p->htop;
 
1872
            p->htop += need;
 
1873
            arg1 = big_div(arg1, arg2, hp);
 
1874
            trim_heap(p, hp, arg1);
 
1875
            if (is_nil(arg1)) {
 
1876
                p->freason = SYSTEM_LIMIT;
 
1877
                return THE_NON_VALUE;
 
1878
            }
 
1879
        }
 
1880
        return arg1;
 
1881
    default:
 
1882
        p->freason = BADARITH;
 
1883
        return THE_NON_VALUE;
 
1884
    }
 
1885
}
 
1886
 
 
1887
Eterm
 
1888
erts_gc_int_rem(Process* p, Eterm* reg, Uint live)
 
1889
{
 
1890
    Eterm arg1;
 
1891
    Eterm arg2;
 
1892
    Eterm tmp_big1[2];
 
1893
    Eterm tmp_big2[2];
 
1894
    int ires;
 
1895
 
 
1896
    arg1 = reg[live];
 
1897
    arg2 = reg[live+1];
 
1898
    switch (NUMBER_CODE(arg1, arg2)) {
 
1899
    case BIG_SMALL:
 
1900
        arg2 = small_to_big(signed_val(arg2), tmp_big2);
 
1901
        goto L_big_rem;
 
1902
    case SMALL_BIG:
 
1903
        if (arg1 != make_small(MIN_SMALL)) {
 
1904
            return arg1;
 
1905
        }
 
1906
        arg1 = small_to_big(signed_val(arg1), tmp_big1);
 
1907
        /*FALLTHROUGH*/
 
1908
    case BIG_BIG:
 
1909
    L_big_rem:
 
1910
        ires = big_ucomp(arg1, arg2);
 
1911
        if (ires == 0) {
 
1912
            arg1 = SMALL_ZERO;
 
1913
        } else if (ires > 0) {
 
1914
            Eterm* hp;
 
1915
            Uint need = BIG_NEED_SIZE(big_size(arg1));
 
1916
 
 
1917
            if (ERTS_NEED_GC(p, need)) {
 
1918
                erts_garbage_collect(p, need, reg, live+2);
 
1919
                if (arg1 != make_big(tmp_big1)) {
 
1920
                    arg1 = reg[live];
 
1921
                }
 
1922
                if (arg2 != make_big(tmp_big2)) {
 
1923
                    arg2 = reg[live+1];
 
1924
                }
 
1925
            }
 
1926
            hp = p->htop;
 
1927
            p->htop += need;
 
1928
            arg1 = big_rem(arg1, arg2, hp);
 
1929
            trim_heap(p, hp, arg1);
 
1930
            if (is_nil(arg1)) {
 
1931
                p->freason = SYSTEM_LIMIT;
 
1932
                return THE_NON_VALUE;
 
1933
            }
 
1934
        }
 
1935
        return arg1;
 
1936
    default:
 
1937
        p->freason = BADARITH;
 
1938
        return THE_NON_VALUE;
 
1939
    }
 
1940
}
 
1941
 
 
1942
#define DEFINE_GC_LOGIC_FUNC(func)                                              \
 
1943
Eterm erts_gc_##func(Process* p, Eterm* reg, Uint live)                         \
 
1944
{                                                                               \
 
1945
    Eterm arg1;                                                                 \
 
1946
    Eterm arg2;                                                                 \
 
1947
    Eterm tmp_big1[2];                                                          \
 
1948
    Eterm tmp_big2[2];                                                          \
 
1949
    Eterm* hp;                                                                  \
 
1950
    int need;                                                                   \
 
1951
                                                                                \
 
1952
    arg1 = reg[live];                                                           \
 
1953
    arg2 = reg[live+1];                                                         \
 
1954
    switch (NUMBER_CODE(arg1, arg2)) {                                          \
 
1955
    case SMALL_BIG:                                                             \
 
1956
        arg1 = small_to_big(signed_val(arg1), tmp_big1);                        \
 
1957
        need = BIG_NEED_SIZE(big_size(arg2) + 1);                               \
 
1958
        if (ERTS_NEED_GC(p, need)) {                                            \
 
1959
            erts_garbage_collect(p, need, reg, live+2);                         \
 
1960
            arg2 = reg[live+1];                                                 \
 
1961
        }                                                                       \
 
1962
        break;                                                                  \
 
1963
    case BIG_SMALL:                                                             \
 
1964
        arg2 = small_to_big(signed_val(arg2), tmp_big2);                        \
 
1965
        need = BIG_NEED_SIZE(big_size(arg1) + 1);                               \
 
1966
        if (ERTS_NEED_GC(p, need)) {                                            \
 
1967
            erts_garbage_collect(p, need, reg, live+2);                         \
 
1968
            arg1 = reg[live];                                                   \
 
1969
        }                                                                       \
 
1970
        break;                                                                  \
 
1971
    case BIG_BIG:                                                               \
 
1972
        need = BIG_NEED_SIZE(MAX(big_size(arg1), big_size(arg2)) + 1);          \
 
1973
        if (ERTS_NEED_GC(p, need)) {                                            \
 
1974
            erts_garbage_collect(p, need, reg, live+2);                         \
 
1975
            arg1 = reg[live];                                                   \
 
1976
            arg2 = reg[live+1];                                                 \
 
1977
        }                                                                       \
 
1978
        break;                                                                  \
 
1979
    default:                                                                    \
 
1980
        p->freason = BADARITH;                                                  \
 
1981
        return THE_NON_VALUE;                                                   \
 
1982
    }                                                                           \
 
1983
    hp = p->htop;                                                               \
 
1984
    p->htop += need;                                                            \
 
1985
    arg1 = big_##func(arg1, arg2, hp);                                          \
 
1986
    trim_heap(p, hp, arg1);                                                     \
 
1987
    return arg1;                                                                \
 
1988
}
 
1989
 
 
1990
DEFINE_GC_LOGIC_FUNC(band)
 
1991
DEFINE_GC_LOGIC_FUNC(bor)
 
1992
DEFINE_GC_LOGIC_FUNC(bxor)
 
1993
 
 
1994
Eterm erts_gc_bnot(Process* p, Eterm* reg, Uint live)
 
1995
{
 
1996
    Eterm result;
 
1997
    Eterm arg;
 
1998
    Uint need;
 
1999
    Eterm* bigp;
 
2000
 
 
2001
    arg = reg[live];
 
2002
    if (is_not_big(arg)) {
 
2003
        p->freason = BADARITH;
 
2004
        return NIL;
 
2005
    } else {
 
2006
        need = BIG_NEED_SIZE(big_size(arg)+1);
 
2007
        if (ERTS_NEED_GC(p, need)) {
 
2008
            erts_garbage_collect(p, need, reg, live+1);
 
2009
            arg = reg[live];
 
2010
        }
 
2011
        bigp = p->htop;
 
2012
        p->htop += need;
 
2013
        result = big_bnot(arg, bigp);
 
2014
        trim_heap(p, bigp, result);
 
2015
        if (is_nil(result)) {
 
2016
            p->freason = SYSTEM_LIMIT;
 
2017
            return NIL;
 
2018
        }
 
2019
    }
 
2020
    return result;
 
2021
 
2022
 
 
2023
#endif