ecma_bigint_add_sub (ecma_value_t left_value, /**< left BigInt value */
                     ecma_value_t right_value, /**< right BigInt value */
                     bool is_add) /**< true if add operation should be performed */
{
  JERRY_ASSERT (ecma_is_value_bigint (left_value) && ecma_is_value_bigint (right_value));

  if (right_value == ECMA_BIGINT_ZERO)
  {
    return ecma_copy_value (left_value);
  }

  ecma_extended_primitive_t *right_p = ecma_get_extended_primitive_from_value (right_value);

  if (left_value == ECMA_BIGINT_ZERO)
  {
    if (!is_add)
    {
      return ecma_bigint_negate (right_p);
    }

    ecma_ref_extended_primitive (right_p);
    return right_value;
  }

  ecma_extended_primitive_t *left_p = ecma_get_extended_primitive_from_value (left_value);
  uint32_t sign = is_add ? 0 : ECMA_BIGINT_SIGN;

  if (((left_p->u.bigint_sign_and_size ^ right_p->u.bigint_sign_and_size) & ECMA_BIGINT_SIGN) == sign)
  {
    ecma_extended_primitive_t *result_p = ecma_big_uint_add (left_p, right_p);

    if (JERRY_UNLIKELY (result_p == NULL))
    {
      return ecma_bigint_raise_memory_error ();
    }

    result_p->u.bigint_sign_and_size |= left_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN;
    return ecma_make_extended_primitive_value (result_p, ECMA_TYPE_BIGINT);
  }

  int compare_result = ecma_big_uint_compare (left_p, right_p);
  ecma_extended_primitive_t *result_p;

  if (compare_result == 0)
  {
    return ECMA_BIGINT_ZERO;
  }

  if (compare_result > 0)
  {
    sign = left_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN;
    result_p = ecma_big_uint_sub (left_p, right_p);
  }
  else
  {
    sign = right_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN;

    if (!is_add)
    {
      sign ^= ECMA_BIGINT_SIGN;
    }

    result_p = ecma_big_uint_sub (right_p, left_p);
  }

  if (JERRY_UNLIKELY (result_p == NULL))
  {
    return ecma_bigint_raise_memory_error ();
  }

  result_p->u.bigint_sign_and_size |= sign;
  return ecma_make_extended_primitive_value (result_p, ECMA_TYPE_BIGINT);
} /* ecma_bigint_add_sub */
ecma_bigint_add_sub (ecma_value_t left_value,  
                     ecma_value_t right_value,  
                     bool is_add)  
{
  JERRY_ASSERT (ecma_is_value_bigint (left_value) && ecma_is_value_bigint (right_value));

  if (right_value == ECMA_BIGINT_ZERO)
  {
    return ecma_copy_value (left_value);
  }

  ecma_extended_primitive_t *right_p = ecma_get_extended_primitive_from_value (right_value);

  if (left_value == ECMA_BIGINT_ZERO)
  {
    if (!is_add)
    {
      return ecma_bigint_negate (right_p);
    }

    ecma_ref_extended_primitive (right_p);
    return right_value;
  }

  ecma_extended_primitive_t *left_p = ecma_get_extended_primitive_from_value (left_value);
  uint32_t sign = is_add ? 0 : ECMA_BIGINT_SIGN;

  if (((left_p->u.bigint_sign_and_size ^ right_p->u.bigint_sign_and_size) & ECMA_BIGINT_SIGN) == sign)
  {
    ecma_extended_primitive_t *result_p = ecma_big_uint_add (left_p, right_p);

    if (JERRY_UNLIKELY (result_p == NULL))
    {
      return ecma_bigint_raise_memory_error ();
    }

    result_p->u.bigint_sign_and_size |= left_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN;
    return ecma_make_extended_primitive_value (result_p, ECMA_TYPE_BIGINT);
  }

  int compare_result = ecma_big_uint_compare (left_p, right_p);
  ecma_extended_primitive_t *result_p;

  if (compare_result == 0)
  {
    return ECMA_BIGINT_ZERO;
  }

  if (compare_result > 0)
  {
    sign = left_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN;
    result_p = ecma_big_uint_sub (left_p, right_p);
  }
  else
  {
    sign = right_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN;

    if (!is_add)
    {
      sign ^= ECMA_BIGINT_SIGN;
    }

    result_p = ecma_big_uint_sub (right_p, left_p);
  }

  if (JERRY_UNLIKELY (result_p == NULL))
  {
    return ecma_bigint_raise_memory_error ();
  }

  result_p->u.bigint_sign_and_size |= sign;
  return ecma_make_extended_primitive_value (result_p, ECMA_TYPE_BIGINT);
}  