diff options
Diffstat (limited to 'erts/emulator/beam/arith_instrs.tab')
-rw-r--r-- | erts/emulator/beam/arith_instrs.tab | 80 |
1 files changed, 43 insertions, 37 deletions
diff --git a/erts/emulator/beam/arith_instrs.tab b/erts/emulator/beam/arith_instrs.tab index 91fe21e161..67cd7c6a2a 100644 --- a/erts/emulator/beam/arith_instrs.tab +++ b/erts/emulator/beam/arith_instrs.tab @@ -226,16 +226,12 @@ i_bsr := shift.setup_bsr.execute; shift.head() { Eterm Op1, Op2; Sint shift_left_count; - Sint ires; - Eterm* bigp; - Eterm tmp_big[2]; - Uint BIF; } shift.setup_bsr(Src1, Src2) { Op1 = $Src1; Op2 = $Src2; - BIF = BIF_bsr_2; + shift_left_count = 0; if (is_small(Op2)) { shift_left_count = -signed_val(Op2); } else if (is_big(Op2)) { @@ -245,15 +241,13 @@ shift.setup_bsr(Src1, Src2) { */ shift_left_count = make_small(bignum_header_is_neg(*big_val(Op2)) ? MAX_SMALL : MIN_SMALL); - } else { - shift_left_count = 0; } } shift.setup_bsl(Src1, Src2) { Op1 = $Src1; Op2 = $Src2; - BIF = BIF_bsl_2; + shift_left_count = 0; if (is_small(Op2)) { shift_left_count = signed_val(Op2); } else if (is_big(Op2)) { @@ -271,66 +265,65 @@ shift.setup_bsl(Src1, Src2) { */ shift_left_count = MAX_SMALL; } - } else { - shift_left_count = 0; } } shift.execute(Fail, Live, Dst) { + Uint big_words_needed; + if (is_small(Op1)) { - ires = signed_val(Op1); - if (shift_left_count == 0 || ires == 0) { + Sint int_res = signed_val(Op1); + if (shift_left_count == 0 || int_res == 0) { if (is_not_integer(Op2)) { - c_p->freason = BADARITH; - $BIF_ERROR_ARITY_2($Fail, BIF, Op1, Op2); + goto shift_error; } - if (ires == 0) { + if (int_res == 0) { $Dst = Op1; $NEXT0(); } } else if (shift_left_count < 0) { /* Right shift */ + Eterm bsr_res; shift_left_count = -shift_left_count; if (shift_left_count >= SMALL_BITS-1) { - $Dst = (ires < 0) ? SMALL_MINUS_ONE : SMALL_ZERO; + bsr_res = (int_res < 0) ? SMALL_MINUS_ONE : SMALL_ZERO; } else { - $Dst = make_small(ires >> shift_left_count); + bsr_res = make_small(int_res >> shift_left_count); } + $Dst = bsr_res; $NEXT0(); } else if (shift_left_count < SMALL_BITS-1) { /* Left shift */ - if ((ires > 0 && - ((~(Uint)0 << ((SMALL_BITS-1)-shift_left_count)) & - ires) == 0) || - ((~(Uint)0 << ((SMALL_BITS-1)-shift_left_count)) & - ~ires) == 0) { - $Dst = make_small(ires << shift_left_count); + if ((int_res > 0 && + ((~(Uint)0 << ((SMALL_BITS-1)-shift_left_count)) & int_res) == 0) || + ((~(Uint)0 << ((SMALL_BITS-1)-shift_left_count)) & ~int_res) == 0) { + $Dst = make_small(int_res << shift_left_count); $NEXT0(); } } - ires = 1; /* big_size(small_to_big(Op1)) */ + big_words_needed = 1; /* big_size(small_to_big(Op1)) */ goto big_shift; } else if (is_big(Op1)) { if (shift_left_count == 0) { if (is_not_integer(Op2)) { - c_p->freason = BADARITH; - $BIF_ERROR_ARITY_2($Fail, BIF, Op1, Op2); + goto shift_error; } $Dst = Op1; $NEXT0(); } - ires = big_size(Op1); + big_words_needed = big_size(Op1); big_shift: if (shift_left_count > 0) { /* Left shift. */ - ires += (shift_left_count / D_EXP); + big_words_needed += (shift_left_count / D_EXP); } else { /* Right shift. */ - if (ires <= (-shift_left_count / D_EXP)) { - ires = 3; /* ??? */ + if (big_words_needed <= (-shift_left_count / D_EXP)) { + big_words_needed = 3; /* ??? */ } else { - ires -= (-shift_left_count / D_EXP); + big_words_needed -= (-shift_left_count / D_EXP); } } { - ires = BIG_NEED_SIZE(ires+1); + Eterm tmp_big[2]; + Sint big_need_size = BIG_NEED_SIZE(big_words_needed+1); /* * Slightly conservative check the size to avoid @@ -338,15 +331,14 @@ shift.execute(Fail, Live, Dst) { * clearly would overflow the arity in the header * word. */ - if (ires-8 > BIG_ARITY_MAX) { + if (big_need_size-8 > BIG_ARITY_MAX) { $SYSTEM_LIMIT($Fail); } - $GC_TEST_PRESERVE(ires+1, $Live, Op1); + $GC_TEST_PRESERVE(big_need_size+1, $Live, Op1); if (is_small(Op1)) { Op1 = small_to_big(signed_val(Op1), tmp_big); } - bigp = HTOP; - Op1 = big_lshift(Op1, shift_left_count, bigp); + Op1 = big_lshift(Op1, shift_left_count, HTOP); if (is_big(Op1)) { HTOP += bignum_header_arity(*HTOP) + 1; } @@ -369,8 +361,22 @@ shift.execute(Fail, Live, Dst) { /* * One or more non-integer arguments. */ + shift_error: c_p->freason = BADARITH; - $BIF_ERROR_ARITY_2($Fail, BIF, Op1, Op2); + if ($Fail) { + $FAIL($Fail); + } else { + reg[0] = Op1; + reg[1] = Op2; + SWAPOUT; + if (I[0] == (BeamInstr) OpCode(i_bsl_ssjtd)) { + I = handle_error(c_p, I, reg, &bif_export[BIF_bsl_2]->info.mfa); + } else { + ASSERT(I[0] == (BeamInstr) OpCode(i_bsr_ssjtd)); + I = handle_error(c_p, I, reg, &bif_export[BIF_bsr_2]->info.mfa); + } + goto post_error_handling; + } } i_int_bnot(Fail, Src, Live, Dst) { |