Skip to content

Commit

Permalink
Simplify arithmetic with a bignum and a small
Browse files Browse the repository at this point in the history
  • Loading branch information
bjorng committed Aug 24, 2023
1 parent dec8215 commit 920f26c
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 22 deletions.
16 changes: 13 additions & 3 deletions erts/emulator/beam/big.c
Original file line number Diff line number Diff line change
Expand Up @@ -2900,12 +2900,22 @@ Eterm big_plus_small(Eterm x, Uint y, Eterm *r)
BIG_V(r)), (short) BIG_SIGN(xp));
}

Eterm big_times_small(Eterm x, Uint y, Eterm *r)
Eterm big_mul_small(Eterm x, Eterm y, Eterm *r)
{
Eterm* xp = big_val(x);
Sint val;
short sgn = BIG_SIGN(xp);

return big_norm(r, D_mul(BIG_V(xp),BIG_SIZE(xp), (ErtsDigit) y,
BIG_V(r)), (short) BIG_SIGN(xp));
ASSERT(is_small(y));
val = signed_val(y);
if (val < 0) {
val = -val;
sgn = !sgn;
}

return big_norm(r, D_mul(BIG_V(xp), BIG_SIZE(xp),
(ErtsDigit) val, BIG_V(r)),
sgn);
}

/*
Expand Down
2 changes: 1 addition & 1 deletion erts/emulator/beam/big.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ Eterm big_div(Eterm, Eterm, Eterm*);
Eterm big_rem(Eterm, Eterm, Eterm*);

Eterm big_plus_small(Eterm, Uint, Eterm*);
Eterm big_times_small(Eterm, Uint, Eterm*);
Eterm big_mul_small(Eterm, Eterm, Eterm*);

Eterm big_band(Eterm, Eterm, Eterm*);
Eterm big_bor(Eterm, Eterm, Eterm*);
Expand Down
53 changes: 35 additions & 18 deletions erts/emulator/beam/erl_arith.c
Original file line number Diff line number Diff line change
Expand Up @@ -672,8 +672,6 @@ erts_mixed_minus(Process* p, Eterm arg1, Eterm arg2)
Eterm
erts_mixed_times(Process* p, Eterm arg1, Eterm arg2)
{
DECLARE_TMP(tmp_big1,0,p);
DECLARE_TMP(tmp_big2,1,p);
Eterm hdr;
Eterm res;
FloatDef f1, f2;
Expand Down Expand Up @@ -746,9 +744,23 @@ erts_mixed_times(Process* p, Eterm arg1, Eterm arg2)
return(SMALL_ZERO);
if (arg1 == SMALL_ONE)
return(arg2);
arg1 = small_to_big(signed_val(arg1), tmp_big1);
sz = 2 + big_size(arg2);
goto do_big;
sz = big_size(arg2) + 1;
need_heap = BIG_NEED_SIZE(sz);
#ifdef DEBUG
need_heap++;
#endif
hp = HeapFragOnlyAlloc(p, need_heap);
#ifdef DEBUG
hp[need_heap-1] = ERTS_HOLE_MARKER;
#endif
res = big_mul_small(arg2, arg1, hp);
ASSERT(hp[need_heap-1] == ERTS_HOLE_MARKER);
maybe_shrink(p, hp, res, need_heap);
if (is_nil(res)) {
p->freason = SYSTEM_LIMIT;
return THE_NON_VALUE;
}
return res;
case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE):
f1.fd = signed_val(arg1);
GET_DOUBLE(arg2, f2);
Expand All @@ -773,9 +785,24 @@ erts_mixed_times(Process* p, Eterm arg1, Eterm arg2)
return(SMALL_ZERO);
if (arg2 == SMALL_ONE)
return(arg1);
arg2 = small_to_big(signed_val(arg2), tmp_big2);
sz = 2 + big_size(arg1);
goto do_big;
sz = big_size(arg1) + 1;
need_heap = BIG_NEED_SIZE(sz);
#ifdef DEBUG
need_heap++;
#endif
hp = HeapFragOnlyAlloc(p, need_heap);

#ifdef DEBUG
hp[need_heap-1] = ERTS_HOLE_MARKER;
#endif
res = big_mul_small(arg1, arg2, hp);
ASSERT(hp[need_heap-1] == ERTS_HOLE_MARKER);
maybe_shrink(p, hp, res, need_heap);
if (is_nil(res)) {
p->freason = SYSTEM_LIMIT;
return THE_NON_VALUE;
}
return res;
default:
goto badarith;
}
Expand All @@ -787,26 +814,16 @@ erts_mixed_times(Process* p, Eterm arg1, Eterm arg2)
sz1 = big_size(arg1);
sz2 = big_size(arg2);
sz = sz1 + sz2;

do_big:
need_heap = BIG_NEED_SIZE(sz);
#ifdef DEBUG
need_heap++;
#endif
hp = HeapFragOnlyAlloc(p, need_heap);

#ifdef DEBUG
hp[need_heap-1] = ERTS_HOLE_MARKER;
#endif
res = big_times(arg1, arg2, hp);
ASSERT(hp[need_heap-1] == ERTS_HOLE_MARKER);

/*
* Note that the result must be big in this case, since
* at least one operand was big to begin with, and
* the absolute value of the other is > 1.
*/

maybe_shrink(p, hp, res, need_heap);
if (is_nil(res)) {
p->freason = SYSTEM_LIMIT;
Expand Down

0 comments on commit 920f26c

Please sign in to comment.