diff --git a/src/libAtomVM/bif.c b/src/libAtomVM/bif.c index f0995657d..92460b699 100644 --- a/src/libAtomVM/bif.c +++ b/src/libAtomVM/bif.c @@ -1427,24 +1427,47 @@ term bif_erlang_float_1(Context *ctx, uint32_t fail_label, int live, term arg1) } typedef int64_t (*bitwise_op)(int64_t a, int64_t b); +typedef size_t (*bitwise_big_op)( + const intn_digit_t m[], size_t m_len, intn_integer_sign_t m_sign, + const intn_digit_t n[], size_t n_len, intn_integer_sign_t n_sign, + intn_digit_t out[], intn_integer_sign_t *out_sign); -static inline term bitwise_helper(Context *ctx, uint32_t fail_label, int live, term arg1, term arg2, bitwise_op op) +static inline term bitwise_helper( + Context *ctx, uint32_t fail_label, int live, term arg1, term arg2, bitwise_op op, bitwise_big_op big_op) { - UNUSED(live); + if (LIKELY(term_is_any_integer(arg1) && term_is_any_integer(arg2))) { + size_t arg1_size = term_is_integer(arg1) ? 0 : term_boxed_size(arg1); + size_t arg2_size = term_is_integer(arg2) ? 0 : term_boxed_size(arg2); + if (MAX(arg1_size, arg2_size) <= BOXED_TERMS_REQUIRED_FOR_INT64) { + int64_t a = term_maybe_unbox_int64(arg1); + int64_t b = term_maybe_unbox_int64(arg2); + int64_t result = op(a, b); - if (UNLIKELY(!term_is_any_integer(arg1) || !term_is_any_integer(arg2))) { +#if BOXED_TERMS_REQUIRED_FOR_INT64 > 1 + return make_maybe_boxed_int64(ctx, fail_label, live, result); +#else + return make_maybe_boxed_int(ctx, fail_label, live, result); +#endif + } else { + intn_digit_t tmp_buf1[INTN_INT64_LEN]; + intn_digit_t tmp_buf2[INTN_INT64_LEN]; + intn_digit_t *m; + size_t m_len; + intn_integer_sign_t m_sign; + intn_digit_t *n; + size_t n_len; + intn_integer_sign_t n_sign; + args_to_bigint(arg1, arg2, tmp_buf1, tmp_buf2, &m, &m_len, &m_sign, &n, &n_len, &n_sign); + + intn_digit_t bigres[INTN_MAX_RES_LEN]; + intn_integer_sign_t bigres_sign; + size_t bigres_len = big_op(m, m_len, m_sign, n, n_len, n_sign, bigres, &bigres_sign); + + return make_bigint(ctx, fail_label, live, bigres, bigres_len, bigres_sign); + } + } else { RAISE_ERROR_BIF(fail_label, BADARITH_ATOM); } - - int64_t a = term_maybe_unbox_int64(arg1); - int64_t b = term_maybe_unbox_int64(arg2); - int64_t result = op(a, b); - - #if BOXED_TERMS_REQUIRED_FOR_INT64 > 1 - return make_maybe_boxed_int64(ctx, fail_label, live, result); - #else - return make_maybe_boxed_int(ctx, fail_label, live, result); - #endif } static inline int64_t bor(int64_t a, int64_t b) @@ -1457,7 +1480,7 @@ term bif_erlang_bor_2(Context *ctx, uint32_t fail_label, int live, term arg1, te if (LIKELY(term_is_integer(arg1) && term_is_integer(arg2))) { return arg1 | arg2; } else { - return bitwise_helper(ctx, fail_label, live, arg1, arg2, bor); + return bitwise_helper(ctx, fail_label, live, arg1, arg2, bor, intn_bormn); } } @@ -1471,7 +1494,7 @@ term bif_erlang_band_2(Context *ctx, uint32_t fail_label, int live, term arg1, t if (LIKELY(term_is_integer(arg1) && term_is_integer(arg2))) { return arg1 & arg2; } else { - return bitwise_helper(ctx, fail_label, live, arg1, arg2, band); + return bitwise_helper(ctx, fail_label, live, arg1, arg2, band, intn_bandmn); } } @@ -1485,51 +1508,142 @@ term bif_erlang_bxor_2(Context *ctx, uint32_t fail_label, int live, term arg1, t if (LIKELY(term_is_integer(arg1) && term_is_integer(arg2))) { return (arg1 ^ arg2) | TERM_INTEGER_TAG; } else { - return bitwise_helper(ctx, fail_label, live, arg1, arg2, bxor); + return bitwise_helper(ctx, fail_label, live, arg1, arg2, bxor, intn_bxormn); } } -typedef int64_t (*bitshift_op)(int64_t a, avm_int_t b); - -static inline term bitshift_helper(Context *ctx, uint32_t fail_label, int live, term arg1, term arg2, bitshift_op op) +#if 0 +static inline int32_t int32_bsr(int32_t n, unsigned int rshift) { - UNUSED(live); + return (int32_t) ((n < 0) ? ~(~((uint32_t ) n) >> rshift) : (((uint32_t) n) >> rshift)); +} - if (UNLIKELY(!term_is_any_integer(arg1) || !term_is_integer(arg2))) { - RAISE_ERROR_BIF(fail_label, BADARITH_ATOM); +static inline bool int32_bsl_overflow(int32_t n, unsigned int lshift, int32_t *out) +{ + // + if ((n != 0) && (lshift > 32)) { + *out = 0; + return (n != 0); } + // - int64_t a = term_maybe_unbox_int64(arg1); - avm_int_t b = term_to_int(arg2); - int64_t result = op(a, b); + int32_t res = (int32_t) (((uint32_t) n) << lshift); + *out = res; + int32_t check = int32_bsr(res, lshift); + return check != n; +} - #if BOXED_TERMS_REQUIRED_FOR_INT64 > 1 - return make_maybe_boxed_int64(ctx, fail_label, live, result); - #else - return make_maybe_boxed_int(ctx, fail_label, live, result); - #endif +static inline int32_t int32_bsr_safe(int32_t n, unsigned int rshift) +{ + if (rshift > 32) { + return n < 0 ? -1 : 0; + } + return int32_bsr(n, rshift); } +#endif -static inline int64_t bsl(int64_t a, avm_int_t b) +static inline int64_t int64_bsr(int64_t n, unsigned int rshift) { - // TODO check for overflow - return a << b; + return (int64_t) ((n < 0) ? ~(~((uint64_t ) n) >> rshift) : (((uint64_t) n) >> rshift)); } -term bif_erlang_bsl_2(Context *ctx, uint32_t fail_label, int live, term arg1, term arg2) +static inline bool int64_bsl_overflow(int64_t n, unsigned int lshift, int64_t *out) +{ + // + if (lshift > 64) { + *out = 0; + return (n != 0); + } + // + + int64_t res = (int64_t) (((uint64_t) n) << lshift); + *out = res; + int64_t check = int64_bsr(res, lshift); + return check != n; +} + +static inline int64_t int64_bsr_safe(int64_t n, unsigned int rshift) { - return bitshift_helper(ctx, fail_label, live, arg1, arg2, bsl); + if (rshift > 64) { + return n < 0 ? -1 : 0; + } + return int64_bsr(n, rshift); } -static inline int64_t bsr(int64_t a, avm_int_t b) +term bif_erlang_bsl_2(Context *ctx, uint32_t fail_label, int live, term arg1, term arg2) { - // TODO check for underflow - return a >> b; + if (LIKELY(term_is_any_integer(arg1) && term_is_any_integer(arg2))) { + size_t arg1_size = term_is_integer(arg1) ? 0 : term_boxed_size(arg1); + avm_int_t b = term_to_int(arg2); + if (arg1_size <= BOXED_TERMS_REQUIRED_FOR_INT64) { + int64_t a = term_maybe_unbox_int64(arg1); + //if (uint64_leading_zeros(a) >= b) { + int64_t result; + if (!int64_bsl_overflow(a, b, &result)) { + #if BOXED_TERMS_REQUIRED_FOR_INT64 > 1 + return make_maybe_boxed_int64(ctx, fail_label, live, result); + #else + return make_maybe_boxed_int(ctx, fail_label, live, result); + #endif + } + } + + intn_digit_t tmp_buf1[INTN_INT64_LEN]; + intn_digit_t tmp_buf2[INTN_INT64_LEN]; + intn_digit_t *m; + size_t m_len; + intn_integer_sign_t m_sign; + intn_digit_t *n; + size_t n_len; + intn_integer_sign_t n_sign; + args_to_bigint(arg1, arg2, tmp_buf1, tmp_buf2, &m, &m_len, &m_sign, &n, &n_len, &n_sign); + + intn_digit_t bigres[INTN_MAX_RES_LEN]; + size_t bigres_len = intn_bsl(m, m_len, b, bigres); + + return make_bigint(ctx, fail_label, live, bigres, bigres_len, m_sign); + + } else { + RAISE_ERROR_BIF(fail_label, BADARITH_ATOM); + } } term bif_erlang_bsr_2(Context *ctx, uint32_t fail_label, int live, term arg1, term arg2) { - return bitshift_helper(ctx, fail_label, live, arg1, arg2, bsr); + if (LIKELY(term_is_any_integer(arg1) && term_is_any_integer(arg2))) { + size_t arg1_size = term_is_integer(arg1) ? 0 : term_boxed_size(arg1); + + avm_int_t b = term_to_int(arg2); + + if (arg1_size <= BOXED_TERMS_REQUIRED_FOR_INT64) { + uint64_t a = (uint64_t) term_maybe_unbox_int64(arg1); + int64_t result = int64_bsr_safe(a, b); + + #if BOXED_TERMS_REQUIRED_FOR_INT64 > 1 + return make_maybe_boxed_int64(ctx, fail_label, live, result); + #else + return make_maybe_boxed_int(ctx, fail_label, live, result); + #endif + } + + intn_digit_t tmp_buf1[INTN_INT64_LEN]; + intn_digit_t tmp_buf2[INTN_INT64_LEN]; + intn_digit_t *m; + size_t m_len; + intn_integer_sign_t m_sign; + intn_digit_t *n; + size_t n_len; + intn_integer_sign_t n_sign; + args_to_bigint(arg1, arg2, tmp_buf1, tmp_buf2, &m, &m_len, &m_sign, &n, &n_len, &n_sign); + + intn_digit_t bigres[INTN_MAX_RES_LEN]; + size_t bigres_len = intn_bsr(m, m_len, m_sign, b, bigres); + + return make_bigint(ctx, fail_label, live, bigres, bigres_len, m_sign); + + } else { + RAISE_ERROR_BIF(fail_label, BADARITH_ATOM); + } } term bif_erlang_bnot_1(Context *ctx, uint32_t fail_label, int live, term arg1) diff --git a/src/libAtomVM/intn.c b/src/libAtomVM/intn.c index 240dc4194..50965c515 100644 --- a/src/libAtomVM/intn.c +++ b/src/libAtomVM/intn.c @@ -35,6 +35,9 @@ #define MIN(a, b) (((a) < (b)) ? (a) : (b)) #define MAX(a, b) (((a) > (b)) ? (a) : (b)) +static size_t cond_neg_in_place(intn_integer_sign_t sign, intn_digit_t out[]); +static size_t neg_in_place(intn_digit_t out[], size_t len); + /* * Multiplication */ @@ -380,6 +383,296 @@ size_t intn_addmnu( return i; } +static void neg(const intn_digit_t in[], size_t in_len, intn_digit_t out[]) +{ + uint32_t carry = 1; + for (size_t i = 0; i < in_len; i++) { + uint64_t temp = (uint64_t) (~in[i]) + (uint64_t) carry; + out[i] = (uint32_t) temp; + carry = temp >> 32; + } +} + +static void cond_neg( + intn_integer_sign_t sign, const intn_digit_t in[], size_t in_len, intn_digit_t out[]) +{ + if (sign == IntNPositiveInteger) { + memcpy(out, in, sizeof(intn_digit_t) * in_len); + } else { + neg(in, in_len, out); + } +} + +static size_t prepare_working_buf(const intn_digit_t m[], size_t m_len, intn_integer_sign_t m_sign, + const intn_digit_t n[], size_t n_len, intn_integer_sign_t n_sign, const intn_digit_t *b[], + size_t *b_len, intn_integer_sign_t *b_sign, intn_digit_t out[]) +{ + const intn_digit_t *longest; + size_t longest_len; + intn_integer_sign_t longest_sign; + + if (m_len > n_len) { + longest = m; + longest_len = m_len; + longest_sign = m_sign; + *b = n; + *b_len = n_len; + *b_sign = n_sign; + } else { + longest = n; + longest_len = n_len; + longest_sign = n_sign; + *b = m; + *b_len = m_len; + *b_sign = m_sign; + } + + cond_neg(longest_sign, longest, longest_len, out); + return longest_len; +} + +typedef intn_digit_t (*bit_op_t)(intn_digit_t a, intn_digit_t b); + +static inline void signed_bitwise(const intn_digit_t b[], size_t b_len, intn_integer_sign_t b_sign, + intn_digit_t out[], size_t out_len, bit_op_t bit_op) +{ + if (b_sign == IntNPositiveInteger) { + for (size_t i = 0; i < b_len; i++) { + out[i] = bit_op(out[i], b[i]); + } + for (size_t i = b_len; i < out_len; i++) { + out[i] = bit_op(out[i], 0); + } + } else { + uint32_t carry = 1; + for (size_t i = 0; i < b_len; i++) { + uint64_t temp = (uint64_t) (~b[i]) + (uint64_t) carry; + out[i] = bit_op(out[i], (uint32_t) temp); + carry = temp >> 32; + } + if (b_len < out_len) { + out[b_len] = bit_op(out[b_len], (UINT32_MAX) + carry); + } + for (size_t i = b_len + 1; i < out_len; i++) { + out[i] = bit_op(out[i], UINT32_MAX); + } + } +} + +static inline intn_integer_sign_t sign_bitwise( + intn_integer_sign_t m_sign, intn_integer_sign_t n_sign, bit_op_t bit_op) +{ + return (intn_integer_sign_t) bit_op((unsigned int) m_sign, (unsigned int) n_sign) + & IntNNegativeInteger; +} + +// normalizes -0 to 0 +static inline size_t count_and_normalize_sign( + const intn_digit_t num[], size_t len, intn_integer_sign_t sign, intn_integer_sign_t *out_sign) +{ + size_t count = intn_count_digits(num, len); + if ((count == 0) && (sign == IntNNegativeInteger)) { + *out_sign = IntNPositiveInteger; + } else { + *out_sign = sign; + } + return count; +} + +static inline intn_digit_t digit_bor(intn_digit_t a, intn_digit_t b) +{ + return a | b; +} + +size_t intn_bormn(const intn_digit_t m[], size_t m_len, intn_integer_sign_t m_sign, + const intn_digit_t n[], size_t n_len, intn_integer_sign_t n_sign, intn_digit_t out[], + intn_integer_sign_t *out_sign) +{ + intn_digit_t working_buf[INTN_MAX_IN_LEN]; + + const intn_digit_t *b; + size_t b_len; + intn_integer_sign_t b_sign; + + size_t count + = prepare_working_buf(m, m_len, m_sign, n, n_len, n_sign, &b, &b_len, &b_sign, working_buf); + + signed_bitwise(b, b_len, b_sign, working_buf, count, digit_bor); + intn_integer_sign_t res_sign = sign_bitwise(m_sign, n_sign, digit_bor); + + cond_neg(res_sign, working_buf, count, out); + *out_sign = res_sign; + + return count; +} + +static inline intn_digit_t digit_band(intn_digit_t a, intn_digit_t b) +{ + return a & b; +} + +size_t intn_bandmn(const intn_digit_t m[], size_t m_len, intn_integer_sign_t m_sign, + const intn_digit_t n[], size_t n_len, intn_integer_sign_t n_sign, intn_digit_t out[], + intn_integer_sign_t *out_sign) +{ + intn_digit_t working_buf[INTN_MAX_IN_LEN]; + + const intn_digit_t *b; + size_t b_len; + intn_integer_sign_t b_sign; + + size_t count + = prepare_working_buf(m, m_len, m_sign, n, n_len, n_sign, &b, &b_len, &b_sign, working_buf); + + signed_bitwise(b, b_len, b_sign, working_buf, count, digit_bor); + intn_integer_sign_t res_sign = sign_bitwise(m_sign, n_sign, digit_band); + + cond_neg(res_sign, working_buf, count, out); + size_t res_count = count_and_normalize_sign(out, count, res_sign, out_sign); + + return res_count; +} + +static inline intn_digit_t digit_bxor(intn_digit_t a, intn_digit_t b) +{ + return a ^ b; +} + +size_t intn_bxormn(const intn_digit_t m[], size_t m_len, intn_integer_sign_t m_sign, + const intn_digit_t n[], size_t n_len, intn_integer_sign_t n_sign, intn_digit_t out[], + intn_integer_sign_t *out_sign) +{ + intn_digit_t working_buf[INTN_MAX_IN_LEN]; + + const intn_digit_t *b; + size_t b_len; + intn_integer_sign_t b_sign; + + size_t count + = prepare_working_buf(m, m_len, m_sign, n, n_len, n_sign, &b, &b_len, &b_sign, working_buf); + + signed_bitwise(b, b_len, b_sign, working_buf, count, digit_bor); + intn_integer_sign_t res_sign = sign_bitwise(m_sign, n_sign, digit_bxor); + + cond_neg(res_sign, working_buf, count, out); + size_t res_count = count_and_normalize_sign(out, count, res_sign, out_sign); + + return res_count; +} + +#define INTN_BSL_MAX_OUT_LEN 8 + +static inline size_t size_round_to(size_t n, size_t round_to) +{ + return (n + (round_to - 1)) & ~(round_to - 1); +} + +size_t intn_bsl(const uint32_t num[], size_t len, size_t n, uint32_t *out) +{ + size_t digit_bit_size = sizeof(uint32_t) * 8; + + size_t digit_left_bit_shift = n % 32; + size_t right_shift_n = (32 - digit_left_bit_shift); + + size_t counted_digits = intn_count_digits(num, len); + size_t ms_digit_bits = 32 - uint32_nlz(num[counted_digits - 1]); + size_t effective_bits_len = (counted_digits - 1) * digit_bit_size + ms_digit_bits; + size_t new_bits_len = size_round_to(effective_bits_len + n, digit_bit_size); + + size_t new_digits_count = new_bits_len / digit_bit_size; + + if (new_digits_count > INTN_BSL_MAX_OUT_LEN) { + return new_digits_count; + } + + size_t initial_zeros = MIN(n / digit_bit_size, INTN_BSL_MAX_OUT_LEN); + memset(out, 0, initial_zeros * sizeof(uint32_t)); + + if (right_shift_n == 32) { + memcpy(out + initial_zeros, num, len * sizeof(uint32_t)); + return initial_zeros + len; + } + + uint32_t last_digit = 0; + size_t i; + for (i = 0; i < counted_digits; i++) { + uint32_t digit = num[i]; + out[initial_zeros + i] = (digit << digit_left_bit_shift) | (last_digit >> right_shift_n); + last_digit = digit; + } + uint32_t maybe_last_out = (last_digit >> right_shift_n); + + if (initial_zeros + i > new_digits_count) { + abort(); + } + + if (maybe_last_out) { + out[initial_zeros + i] = maybe_last_out; + return initial_zeros + i + 1; + } + + return initial_zeros + i; +} + +void bsru( + const uint32_t num[], size_t effective_bits_len, size_t n, uint32_t last_digit, uint32_t *out) +{ + size_t digit_bit_size = sizeof(uint32_t) * 8; // 32 + + size_t digit_right_bit_shift = n % digit_bit_size; + size_t left_shift_n = (digit_bit_size - digit_right_bit_shift); + + size_t len_in_digits = size_round_to(effective_bits_len, digit_bit_size) / digit_bit_size; + + // caller makes sure that discarded < len_in_digits + size_t discarded = n / digit_bit_size; + + if (left_shift_n == 32) { + memcpy(out, num + discarded, (len_in_digits - discarded) * sizeof(uint32_t)); + return; + } + + size_t i; + for (i = discarded; i < len_in_digits - 1; i++) { + uint32_t next_digit = num[i + 1]; + uint32_t digit = num[i]; + out[i - discarded] = (digit >> digit_right_bit_shift) | (next_digit << left_shift_n); + } + uint32_t maybe_last_out = (num[i] >> digit_right_bit_shift) | (last_digit << left_shift_n); + + if (maybe_last_out) { + out[i - discarded] = maybe_last_out; + } +} + +size_t intn_bsr( + const uint32_t num[], size_t len, intn_integer_sign_t num_sign, size_t n, uint32_t *out) +{ + size_t digit_bit_size = sizeof(uint32_t) * 8; + size_t counted_digits = intn_count_digits(num, len); + size_t ms_digit_bits = 32 - uint32_nlz(num[counted_digits - 1]); + size_t effective_bits_len = (counted_digits - 1) * digit_bit_size + ms_digit_bits; + + if (n >= effective_bits_len) { + out[0] = (num_sign == IntNPositiveInteger) ? 0 : 1; + return 1; + } + + size_t shifted_len = size_round_to(effective_bits_len - n, digit_bit_size) / digit_bit_size; + + if (num_sign == IntNPositiveInteger) { + bsru(num, effective_bits_len, n, 0, out); + + } else { + uint32_t tmp_buf[INTN_MAX_RES_LEN]; + neg(num, counted_digits, tmp_buf); + bsru(tmp_buf, effective_bits_len, n, (uint32_t) -1, out); + neg_in_place(out, shifted_len); + } + + return shifted_len; +} + size_t intn_count_digits(const intn_digit_t *num, size_t num_len) { int i; @@ -623,26 +916,32 @@ int intn_parse( return out_len; } +static size_t neg_in_place(intn_digit_t out[], size_t len) +{ + uint32_t carry = 1; + size_t i; + int last_non_zero = -1; + for (i = 0; i < len; i++) { + uint64_t temp = (uint64_t) (~out[i]) + (uint64_t) carry; + if ((uint32_t) temp != 0) { + last_non_zero = i; + } + out[i] = (uint32_t) temp; + carry = temp >> 32; + } + if (carry) { + abort(); + out[i] = carry; + return i; + } else { + return last_non_zero + 1; + } +} + static size_t cond_neg_in_place(intn_integer_sign_t sign, intn_digit_t out[]) { if (sign == IntNNegativeInteger) { - uint32_t carry = 1; - size_t i; - int last_non_zero = -1; - for (i = 0; i < INTN_MAX_RES_LEN - 1; i++) { - uint64_t temp = (uint64_t) (~out[i]) + (uint64_t) carry; - if ((uint32_t) temp != 0) { - last_non_zero = i; - } - out[i] = (uint32_t) temp; - carry = temp >> 32; - } - if (carry) { - out[i] = carry; - return i; - } else { - return last_non_zero + 1; - } + return neg_in_place(out, INTN_MAX_RES_LEN - 1); } else { return intn_count_digits(out, INTN_MAX_IN_LEN); } diff --git a/src/libAtomVM/intn.h b/src/libAtomVM/intn.h index ee41a19f2..efed1ff6a 100644 --- a/src/libAtomVM/intn.h +++ b/src/libAtomVM/intn.h @@ -73,6 +73,22 @@ void intn_mul_int64(int64_t num1, int64_t num2, intn_digit_t *out, intn_integer_ void print_num(const uint32_t num[], int len); +size_t intn_bormn(const intn_digit_t m[], size_t m_len, intn_integer_sign_t m_sign, + const intn_digit_t n[], size_t n_len, intn_integer_sign_t n_sign, intn_digit_t out[], + intn_integer_sign_t *out_sign); + +size_t intn_bandmn(const intn_digit_t m[], size_t m_len, intn_integer_sign_t m_sign, + const intn_digit_t n[], size_t n_len, intn_integer_sign_t n_sign, intn_digit_t out[], + intn_integer_sign_t *out_sign); + +size_t intn_bxormn(const intn_digit_t m[], size_t m_len, intn_integer_sign_t m_sign, + const intn_digit_t n[], size_t n_len, intn_integer_sign_t n_sign, intn_digit_t out[], + intn_integer_sign_t *out_sign); + +size_t intn_bsl(const uint32_t num[], size_t len, size_t n, uint32_t *out); +size_t intn_bsr( + const uint32_t num[], size_t len, intn_integer_sign_t num_sign, size_t n, uint32_t *out); + size_t intn_count_digits(const intn_digit_t *num, size_t num_len); char *intn_to_string(const intn_digit_t *num, size_t len, intn_integer_sign_t num_sign, int base, diff --git a/src/libAtomVM/utils.h b/src/libAtomVM/utils.h index 14e12e195..f5caace65 100644 --- a/src/libAtomVM/utils.h +++ b/src/libAtomVM/utils.h @@ -324,9 +324,10 @@ static inline __attribute__((always_inline)) func_ptr_t cast_void_to_func_ptr(vo #ifdef __GNUC__ #define UNREACHABLE() \ - __builtin_unreachable() + abort() #else - #define UNREACHABLE(...) + #define UNREACHABLE(...) \ + abort() #endif #if defined(__GNUC__) && !defined(__clang__) diff --git a/tests/erlang_tests/bigint.erl b/tests/erlang_tests/bigint.erl index b7434e870..b238a3c64 100644 --- a/tests/erlang_tests/bigint.erl +++ b/tests/erlang_tests/bigint.erl @@ -53,7 +53,10 @@ start() -> conv_to_from_float() + external_term_decode() + big_literals() + - to_external_term(). + to_external_term() + + test_bor() + + test_bsl() + + test_bsr(). test_mul() -> Expected_INT64_MIN = ?MODULE:pow(-2, 63), @@ -790,6 +793,183 @@ to_external_term() -> 0. +test_bor() -> + Pattern1 = erlang:binary_to_integer( + ?MODULE:id( + <<"10101010101010101010101010101010101010101010101010101010101010100000000000000000">> + ), + 2 + ), + Pattern2 = erlang:binary_to_integer( + ?MODULE:id( + <<"1010101010101010101010101010101010101010101010101010101010101010000000000000000">> + ), + 2 + ), + Res1 = erlang:binary_to_integer( + ?MODULE:id( + <<"11111111111111111111111111111111111111111111111111111111111111110000000000000000">> + ), + 2 + ), + Res1 = Pattern1 bor Pattern2, + + Pattern3 = erlang:binary_to_integer(?MODULE:id(<<"-1">>), 2), + Res2 = ?MODULE:id(-1), + Res2 = Pattern1 bor Pattern3, + + Pattern4 = erlang:binary_to_integer(?MODULE:id(<<"-5555555511111111123456789ABCDEF0">>), 16), + Pattern5 = erlang:binary_to_integer(?MODULE:id(<<"+30303030333333333111111111111111">>), 16), + Res3 = erlang:binary_to_integer(?MODULE:id(<<"-4545454500000000022446688AACCEEF">>), 16), + Res3 = Pattern4 bor Pattern5, + + Pattern6 = erlang:binary_to_integer(?MODULE:id(<<"-30303030333333333111111111111111">>), 16), + Res4 = erlang:binary_to_integer(?MODULE:id(<<"-10101010111111111010101010101001">>), 16), + Res4 = Pattern4 bor Pattern6, + + Pattern7 = erlang:binary_to_integer( + ?MODULE:id(<<"-8000000000000000000000000000000000000000000000000000000000000000">>), 16 + ), + Res5 = ?MODULE:id(-1), + Res5 = ?MODULE:id(Pattern7) bor ?MODULE:id(-1), + + Res6 = Pattern4, + Res6 = ?MODULE:id(Pattern4) bor ?MODULE:id(Pattern7), + + Res7 = erlang:binary_to_integer( + ?MODULE:id(<<"-7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF">>), 16 + ), + Res7 = ?MODULE:id(Pattern7) bor ?MODULE:id(1), + + Pattern8 = erlang:binary_to_integer( + ?MODULE:id(<<"5555555555555555555555555555555555555555555555555555555555555555">>), 16 + ), + Pattern9 = erlang:binary_to_integer( + ?MODULE:id(<<"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA">>), 16 + ), + Res8 = erlang:binary_to_integer( + ?MODULE:id(<<"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF">>), 16 + ), + Res8 = Pattern8 bor Pattern9, + + Res9 = ?MODULE:id(-1), + Res9 = ?MODULE:id(-1) bor Res8, + + 0. + +test_bsl() -> + %% versione negativa + Pattern1 = erlang:binary_to_integer(?MODULE:id(<<"CAFE1234AABBCCDD98765432">>), 16), + <<"CAFE1234AABBCCDD98765432000000">> = erlang:integer_to_binary( + Pattern1 bsl ?MODULE:id(24), 16 + ), + <<"195FC2469557799BB30ECA8640000000">> = erlang:integer_to_binary( + Pattern1 bsl ?MODULE:id(29), 16 + ), + <<"CAFE1234AABBCCDD9876543200000000">> = erlang:integer_to_binary( + Pattern1 bsl ?MODULE:id(32), 16 + ), + <<"657F091A555DE66ECC3B2A19000000000">> = erlang:integer_to_binary( + Pattern1 bsl ?MODULE:id(35), 16 + ), + <<"CAFE1234AABBCCDD98765432000000000000">> = erlang:integer_to_binary( + Pattern1 bsl ?MODULE:id(48), 16 + ), + <<"657F091A555DE66ECC3B2A190000000000000">> = erlang:integer_to_binary( + Pattern1 bsl ?MODULE:id(51), 16 + ), + <<"CAFE1234AABBCCDD987654320000000000000000">> = erlang:integer_to_binary( + Pattern1 bsl ?MODULE:id(64), 16 + ), + <<"CAFE1234AABBCCDD987654320000000000000000000000000000000000000000">> = erlang:integer_to_binary( + Pattern1 bsl ?MODULE:id(160), 16 + ), + <<"657F00000000000000000000000000000000">> = erlang:integer_to_binary( + ?MODULE:id(16#CAFE) bsl ?MODULE:id(127), 16 + ), + <<"CAFE00000000000000000000000000000000">> = erlang:integer_to_binary( + ?MODULE:id(16#CAFE) bsl ?MODULE:id(128), 16 + ), + <<"195FC00000000000000000000000000000000">> = erlang:integer_to_binary( + ?MODULE:id(16#CAFE) bsl ?MODULE:id(129), 16 + ), + <<"CAFE000000000000000000000000000000000000000000000000000000000000">> = erlang:integer_to_binary( + ?MODULE:id(16#CAFE) bsl ?MODULE:id(240), 16 + ), + + Pattern2 = erlang:binary_to_integer(?MODULE:id(<<"-CAFE1234AABBCCDD98765432">>), 16), + <<"-CAFE1234AABBCCDD98765432000000">> = erlang:integer_to_binary( + Pattern2 bsl ?MODULE:id(24), 16 + ), + <<"-195FC2469557799BB30ECA8640000000">> = erlang:integer_to_binary( + Pattern2 bsl ?MODULE:id(29), 16 + ), + <<"-CAFE1234AABBCCDD9876543200000000">> = erlang:integer_to_binary( + Pattern2 bsl ?MODULE:id(32), 16 + ), + <<"-657F091A555DE66ECC3B2A19000000000">> = erlang:integer_to_binary( + Pattern2 bsl ?MODULE:id(35), 16 + ), + <<"-CAFE1234AABBCCDD98765432000000000000">> = erlang:integer_to_binary( + Pattern2 bsl ?MODULE:id(48), 16 + ), + <<"-657F091A555DE66ECC3B2A190000000000000">> = erlang:integer_to_binary( + Pattern2 bsl ?MODULE:id(51), 16 + ), + <<"-CAFE1234AABBCCDD987654320000000000000000">> = erlang:integer_to_binary( + Pattern2 bsl ?MODULE:id(64), 16 + ), + <<"-CAFE1234AABBCCDD987654320000000000000000000000000000000000000000">> = erlang:integer_to_binary( + Pattern2 bsl ?MODULE:id(160), 16 + ), + <<"-657F00000000000000000000000000000000">> = erlang:integer_to_binary( + ?MODULE:id(-16#CAFE) bsl ?MODULE:id(127), 16 + ), + <<"-CAFE00000000000000000000000000000000">> = erlang:integer_to_binary( + ?MODULE:id(-16#CAFE) bsl ?MODULE:id(128), 16 + ), + <<"-195FC00000000000000000000000000000000">> = erlang:integer_to_binary( + ?MODULE:id(-16#CAFE) bsl ?MODULE:id(129), 16 + ), + <<"-CAFE000000000000000000000000000000000000000000000000000000000000">> = erlang:integer_to_binary( + ?MODULE:id(-16#CAFE) bsl ?MODULE:id(240), 16 + ), + + 0. + +test_bsr() -> + erlang:display('bsr'), + + Pattern1 = erlang:binary_to_integer(?MODULE:id(<<"CAFE1234AABBCCDD98765432987654321">>), 16), + <<"CAFE1234AABBCCDD98765432987">> = erlang:integer_to_binary(Pattern1 bsr ?MODULE:id(24), 16), + <<"657F091A555DE66ECC3B2A194C">> = erlang:integer_to_binary(Pattern1 bsr ?MODULE:id(29), 16), + <<"CAFE1234AABBCCDD987654329">> = erlang:integer_to_binary(Pattern1 bsr ?MODULE:id(32), 16), + <<"195FC2469557799BB30ECA865">> = erlang:integer_to_binary(Pattern1 bsr ?MODULE:id(35), 16), + <<"CAFE1234AABBCCDD98765">> = erlang:integer_to_binary(Pattern1 bsr ?MODULE:id(48), 16), + <<"195FC2469557799BB30EC">> = erlang:integer_to_binary(Pattern1 bsr ?MODULE:id(51), 16), + <<"CAFE1234AABBCCDD9">> = erlang:integer_to_binary(Pattern1 bsr ?MODULE:id(64), 16), + <<"C">> = erlang:integer_to_binary(Pattern1 bsr ?MODULE:id(128), 16), + <<"0">> = erlang:integer_to_binary(Pattern1 bsr ?MODULE:id(250), 16), + <<"0">> = erlang:integer_to_binary(Pattern1 bsr ?MODULE:id(256), 16), + <<"0">> = erlang:integer_to_binary(Pattern1 bsr ?MODULE:id(257), 16), + <<"0">> = erlang:integer_to_binary(Pattern1 bsr ?MODULE:id(600), 16), + + Pattern2 = erlang:binary_to_integer(?MODULE:id(<<"-CAFE1234AABBCCDD98765432987654321">>), 16), + <<"-CAFE1234AABBCCDD98765432988">> = erlang:integer_to_binary(Pattern2 bsr ?MODULE:id(24), 16), + <<"-657F091A555DE66ECC3B2A194D">> = erlang:integer_to_binary(Pattern2 bsr ?MODULE:id(29), 16), + <<"-CAFE1234AABBCCDD98765432A">> = erlang:integer_to_binary(Pattern2 bsr ?MODULE:id(32), 16), + <<"-195FC2469557799BB30ECA866">> = erlang:integer_to_binary(Pattern2 bsr ?MODULE:id(35), 16), + <<"-CAFE1234AABBCCDD98766">> = erlang:integer_to_binary(Pattern2 bsr ?MODULE:id(48), 16), + <<"-195FC2469557799BB30ED">> = erlang:integer_to_binary(Pattern2 bsr ?MODULE:id(51), 16), + <<"-CAFE1234AABBCCDDA">> = erlang:integer_to_binary(Pattern2 bsr ?MODULE:id(64), 16), + <<"-D">> = erlang:integer_to_binary(Pattern2 bsr ?MODULE:id(128), 16), + <<"-1">> = erlang:integer_to_binary(Pattern2 bsr ?MODULE:id(250), 16), + <<"-1">> = erlang:integer_to_binary(Pattern2 bsr ?MODULE:id(256), 16), + <<"-1">> = erlang:integer_to_binary(Pattern2 bsr ?MODULE:id(257), 16), + <<"-1">> = erlang:integer_to_binary(Pattern2 bsr ?MODULE:id(600), 16), + + 0. + id(X) -> X. diff --git a/tests/erlang_tests/test_bs_int.erl b/tests/erlang_tests/test_bs_int.erl index 91ac02f90..2ed30235a 100644 --- a/tests/erlang_tests/test_bs_int.erl +++ b/tests/erlang_tests/test_bs_int.erl @@ -32,12 +32,14 @@ start() -> Signedness <- [unsigned, signed] ], - [ - test_bs_ints(Binaries, Size, Endianness, Signedness) - || Size <- [64], - Endianness <- [big, little, native], - Signedness <- [unsigned] - ], + % 64 cannot be used (64 makes use of temporary big integers) + % 48 would be great, but `bitstring_insert_integer` doesn't support 48 bits + % [ + % test_bs_ints(Binaries, Size, Endianness, Signedness) + % || Size <- [48], + % Endianness <- [big, little, native], + % Signedness <- [unsigned] + % ], 0.