Permalink
Browse files

Add a way for var_base to use __int128.

If available - instead of GMP. Summary of the changes:

* CMakeLists.txt - check for __int128 and define the appropriate define
if it exists.

* config.h.in - add define for FCS_USE_INT128_FOR_VAR_BASE

* var_base_int.h - define the common fcs_var_base_int_t type and the
operations on it.

* var_base_reader.h, var_base_writer.h - convert to var_base_int.h.

Also see http://perlweekly.com/archive/234.html and
https://www.nu42.com/2016/01/excellent-optimization-story.html for some
of the inspiration for this change.
  • Loading branch information...
shlomif committed Oct 13, 2016
1 parent 90ef180 commit 49558ea380bbb2812d514ae014ed58da9283e8a0
@@ -400,6 +400,7 @@ INCLUDE(CPack)
include(CheckFunctionExists)
INCLUDE(CheckCCompilerFlag)
INCLUDE(CheckTypeSize)
INCLUDE(FindThreads)
@@ -752,6 +753,11 @@ FOREACH(KEYWORD "inline" "__inline__" "__inline")
ENDIF()
ENDFOREACH()
CHECK_TYPE_SIZE("__int128" INT128 LANGUAGE C)
IF(HAVE_INT128)
SET(FCS_USE_INT128_FOR_VAR_BASE 1)
ENDIF()
CONFIGURE_FILE(
${CMAKE_CURRENT_SOURCE_DIR}/config.h.in
${CMAKE_CURRENT_BINARY_DIR}/config.h
@@ -238,6 +238,8 @@ extern "C" {
#cmakedefine HAVE_VASPRINTF
#cmakedefine FCS_USE_INT128_FOR_VAR_BASE
/* Name of package */
#define PACKAGE "${PACKAGE}"
@@ -0,0 +1,66 @@
/* Copyright (c) 2016 Shlomi Fish
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* var_base_int.h - abstract/wrap either mpz_t or the faster unsigned __int128.
*/
#pragma once
#include "config.h"
#include "rinutils.h"
#ifdef FCS_USE_INT128_FOR_VAR_BASE
typedef unsigned __int128 fcs_var_base_int_t;
#define FCS_var_base_int__init(i) ((i) = 0)
#define FCS_var_base_int__set_ui(i, val) ((i) = (val))
#define FCS_var_base_int__left_shift(i, shift) ((i) <<= (shift))
#define FCS_var_base_int__add(i, i2) ((i) += (i2))
#define FCS_var_base_int__mod_div(i, i_mod, base) \
(i_mod) = (i) % (base); \
(i) /= (base)
#define FCS_var_base_int__get_ui(i) (i)
#define FCS_var_base_int__clear(i)
#define FCS_var_base_int__addmul_ui(i, i2, ui) ((i) += (i2) * (ui))
#define FCS_var_base_int__mul_ui(i, ui) (i) *= (ui)
#define FCS_var_base_int__not_zero(i) ((i) != 0)
#else /* FCS_USE_INT128_FOR_VAR_BASE */
/* Use GMP instead */
#include <gmp.h>
typedef mpz_t fcs_var_base_int_t;
#define FCS_var_base_int__init(i) mpz_init(i)
#define FCS_var_base_int__set_ui(i, val) mpz_set_ui((i), (val))
#define FCS_var_base_int__left_shift(i, shift) mpz_mul_2exp((i), (i), (shift))
#define FCS_var_base_int__add(i, i2) mpz_add((i), (i), (i2))
#define FCS_var_base_int__mod_div(i, i_mod, base) \
mpz_fdiv_qr_ui(i, i_mod, i, base)
#define FCS_var_base_int__get_ui(i) mpz_get_ui(i)
#define FCS_var_base_int__clear(i) mpz_clear(i)
#define FCS_var_base_int__addmul_ui(i, i2, ui) mpz_addmul_ui(i, i2, ui)
#define FCS_var_base_int__mul_ui(i, ui) mpz_mul_ui((i), (i), (ui))
#define FCS_var_base_int__not_zero(i) (mpz_cmp_ui(i, 0) != 0)
#endif /* FCS_USE_INT128_FOR_VAR_BASE */
@@ -28,52 +28,52 @@
#pragma once
#include <assert.h>
#include <gmp.h>
#include "rinutils.h"
#include "var_base_int.h"
typedef struct
{
mpz_t data;
fcs_var_base_int_t data;
/* To avoid memory fragmentation, we keep those here and re use them. */
mpz_t data_byte_offset;
mpz_t r;
fcs_var_base_int_t data_byte_offset;
fcs_var_base_int_t r;
} fcs_var_base_reader_t;
static GCC_INLINE void fc_solve_var_base_reader_init(
fcs_var_base_reader_t *const s)
{
mpz_init(s->data);
mpz_init(s->data_byte_offset);
mpz_init(s->r);
FCS_var_base_int__init(s->data);
FCS_var_base_int__init(s->data_byte_offset);
FCS_var_base_int__init(s->r);
}
static GCC_INLINE void fc_solve_var_base_reader_start(
fcs_var_base_reader_t *const s, const unsigned char *const data,
const size_t data_len)
{
mpz_set_ui(s->data, 0);
FCS_var_base_int__set_ui(s->data, 0);
#define NUM_BITS 8
unsigned long shift_count = 0;
for (size_t count = 0; count < data_len; count++, shift_count += NUM_BITS)
{
mpz_set_ui(s->data_byte_offset, (unsigned long)data[count]);
mpz_mul_2exp(s->data_byte_offset, s->data_byte_offset, shift_count);
mpz_add(s->data, s->data, s->data_byte_offset);
FCS_var_base_int__set_ui(
s->data_byte_offset, (unsigned long)data[count]);
FCS_var_base_int__left_shift(s->data_byte_offset, shift_count);
FCS_var_base_int__add(s->data, s->data_byte_offset);
}
}
static GCC_INLINE int fc_solve_var_base_reader_read(
fcs_var_base_reader_t *const reader, const int base)
{
mpz_fdiv_qr_ui(reader->data, reader->r, reader->data, (unsigned long)base);
FCS_var_base_int__mod_div(reader->data, reader->r, (unsigned long)base);
return (int)mpz_get_ui(reader->r);
return (int)FCS_var_base_int__get_ui(reader->r);
}
static GCC_INLINE void fc_solve_var_base_reader_release(
fcs_var_base_reader_t *s)
fcs_var_base_reader_t *const s)
{
mpz_clear(s->data);
mpz_clear(s->r);
mpz_clear(s->data_byte_offset);
FCS_var_base_int__clear(s->data);
FCS_var_base_int__clear(s->r);
FCS_var_base_int__clear(s->data_byte_offset);
}
@@ -28,30 +28,29 @@
#pragma once
#include <assert.h>
#include <gmp.h>
#include "rinutils.h"
#include "var_base_int.h"
typedef struct
{
mpz_t data;
mpz_t multiplier;
fcs_var_base_int_t data;
fcs_var_base_int_t multiplier;
/* To avoid memory fragmentation, we keep those here and re use them. */
mpz_t remainder;
fcs_var_base_int_t remainder;
} fcs_var_base_writer_t;
static GCC_INLINE void fc_solve_var_base_writer_init(
fcs_var_base_writer_t *const s)
{
mpz_init(s->data);
mpz_init(s->multiplier);
mpz_init(s->remainder);
FCS_var_base_int__init(s->data);
FCS_var_base_int__init(s->multiplier);
FCS_var_base_int__init(s->remainder);
}
static GCC_INLINE void fc_solve_var_base_writer_start(
fcs_var_base_writer_t *const s)
{
mpz_set_ui(s->data, 0);
mpz_set_ui(s->multiplier, 1);
FCS_var_base_int__set_ui(s->data, 0);
FCS_var_base_int__set_ui(s->multiplier, 1);
}
static GCC_INLINE void fc_solve_var_base_writer_write(
@@ -60,9 +59,9 @@ static GCC_INLINE void fc_solve_var_base_writer_write(
assert(item >= 0);
assert(item < base);
mpz_addmul_ui(w->data, w->multiplier, ((unsigned long)item));
FCS_var_base_int__addmul_ui(w->data, w->multiplier, ((unsigned long)item));
mpz_mul_ui(w->multiplier, w->multiplier, ((unsigned long)base));
FCS_var_base_int__mul_ui(w->multiplier, ((unsigned long)base));
}
static GCC_INLINE size_t fc_solve_var_base_writer_get_data(
@@ -71,11 +70,18 @@ static GCC_INLINE size_t fc_solve_var_base_writer_get_data(
size_t count = 0;
#define NUM_BITS 8
while (mpz_cmp_ui(w->data, 0) != 0)
while (FCS_var_base_int__not_zero(w->data))
{
#ifdef FCS_USE_INT128_FOR_VAR_BASE
exported[count++] =
(unsigned char)((w->data) & (((1 << NUM_BITS) - 1)));
w->data >>= NUM_BITS;
#else
mpz_fdiv_r_2exp(w->remainder, w->data, NUM_BITS);
mpz_fdiv_q_2exp(w->data, w->data, NUM_BITS);
exported[count++] = (unsigned char)mpz_get_ui(w->remainder);
exported[count++] =
(unsigned char)FCS_var_base_int__get_ui(w->remainder);
#endif
}
return count;
@@ -84,7 +90,7 @@ static GCC_INLINE size_t fc_solve_var_base_writer_get_data(
static GCC_INLINE void fc_solve_var_base_writer_release(
fcs_var_base_writer_t *const w)
{
mpz_clear(w->data);
mpz_clear(w->multiplier);
mpz_clear(w->remainder);
FCS_var_base_int__clear(w->data);
FCS_var_base_int__clear(w->multiplier);
FCS_var_base_int__clear(w->remainder);
}

0 comments on commit 49558ea

Please sign in to comment.