Skip to content

Commit

Permalink
feat(dwa): add DWA_WIDTH and globals for useful values
Browse files Browse the repository at this point in the history
- add DWA_WIDTH to denote # of bits in dw integers;
- change limit values from functions to globals;
- add globals to represent 0, 1 and -1; and
- add initialization function dwa_prep()
  • Loading branch information
mycoboco committed Jun 1, 2017
1 parent 3f71f41 commit ed4c9b2
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 23 deletions.
50 changes: 46 additions & 4 deletions doc/cdsl/dwa.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,17 +127,24 @@ The following example code shows how to perform 64-bit operations by macroizing
char buf[DWA_BUFSIZE];
sint_t foo = is(-1); // long long foo = -1;
uint_t bar = max; // unsigned long long bar = ULLONG_MAX;

dwa_prep();

printf("%d\n", eu(foo, bar)); // printf("%d\n", foo == bar);
printf("%d\n", es(foo, bar)); // printf("%d\n", foo == (long long)bar);

str(au(foo, bar));
puts(buf); // printf("%lld\n", foo + bar);

`dwa_prep()` prepares `dwa_umax`, `dwa_max` and `dwa_min` properly.

`DWA_BUFSIZE` is useful when preparing a buffer to contain string
representations of double-word integers. Note how conversion and
[type-punning](https://en.wikipedia.org/wiki/Type_punning) between signed and
unsigned types are achieved by properly selected `dwa` functions.

See [`beluga`](https://github.com/mycoboco/beluga) for a more complete example.


## 2. APIs

Expand Down Expand Up @@ -167,15 +174,50 @@ sets `dwa_ubase_t` and `dwa_base_t` to be `unsigned long long` and
`signed long` respectively.


### 2.2. Limit values
### 2.2. Width and useful values

#### `DWA_WIDTH`

The number of bits `dwa_t` contains to represent double-word integers can be
accessed via a macro named `DWA_WIDTH`. For example, you can get a `dwa_t`
value with `n` lower bits set to 1 as follows:

dwa_rshl(dwa_fromuint(-1), DWA_WIDTH - n)

or

dwa_rshl(dwa_neg1, DWA_WIDTH - n)

; see below for `dwa_neg1`.

#### `dwa_umax`, `dwa_max` and `dwa_min`

The range of _unsigned_ `dwa_t` values is [0, `dwa_umax`] and that of _signed_
one [`dwa_min`, `dwa_max`]. These objects, even if not constants, are intended
to play roles of macros from `<limits.h>`. Note that their type is qualifed as
`const` to preclude accidental chage on the values.
one [`dwa_min`, `dwa_max`]. These globals, even if not constants, are intended
to play roles of macros from `<limits.h>`.

`dwa_prep()` has to be invoked for proper initialization before use, and trying
to modify the variables results in undefined behavior.

#### `dwa_0`, `dwa_1` and `dwa_neg1`

When mixing double-word integers with native ones in expressions, converting
integer constants 0, 1 and -1 to double-word ones is frequent and may lead to
performance degradation. These variables can be used to replace, respectively,
calls to `dwa_fromint(0)`, `dwa_fromint(1)` and `dwa_fromint(-1)`, where
`dwa_fromint()` constructs double-word integers from signed base type values.

`dwa_prep()` has to be invoked for proper initialization before use, and trying
to modify the variables results in undefined behavior.

#### `void dwa_prep(void)`

`dwa_prep()` prepares `dwa_umax`, `dwa_max` and `dwa_min` for limit values, and
`dwa_0`, `dwa_1` and `dwa_neg1` for constant values, and must precede their
use.

`dwa_prep()` need not be invoked if those globals are not necessary, and
redundant calls to it have no harm; it is idempotent.

### 2.3. Conversion from and to native integers

Expand Down
56 changes: 39 additions & 17 deletions src/cdsl/dwa.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@
#if CHAR_BIT != 8
#error "USE_W must be disabled with bizarre byte size"
#endif /* CHAR_BIT != 8 */
#define WBIT (CHAR_BIT*sizeof(dwa_base_t)) /* bits in single-word */
#define WBIT (DWA_WIDTH / 2) /* bits in single-word */
#define WBASE ((1U << (WBIT - 1)) * 2.0L) /* single-word radix in long double */
#endif /* USE_W */

#define BASE (1 << 8) /* radix */
#define SIZE (sizeof(((dwa_t *)NULL)->u.v)) /* size of double word in bytes */
#define BASE (1 << 8) /* radix */
#define SIZE (DWA_WIDTH / 8) /* # of bytes in double-word */

#define sign(x) ((x).u.v[SIZE-1] >> 7) /* true if msb is set */

Expand All @@ -31,15 +31,31 @@ long double fmodl(long double, long double);


/* min/max values for dwa_t */
const dwa_t dwa_umax = { -1, -1 },
dwa_max = { -1, (dwa_ubase_t)-1 >> 1 },
dwa_min = { 0, (dwa_ubase_t)1 << (CHAR_BIT*sizeof(dwa_base_t) - 1) };
dwa_t dwa_umax = { -1, -1 };
dwa_t dwa_max = { -1, -1 };
dwa_t dwa_min;

/* useful constants */
dwa_t dwa_0;
dwa_t dwa_1;
dwa_t dwa_neg1 = { -1, -1 };


static const char *map = "0123456789abcdefghijklmnopqrstuvwxyz"; /* mapping for digits */
static char buf[DWA_BUFSIZE]; /* internal buffer */


/*
* prepares useful values to be available
*/
void (dwa_prep)(void)
{
dwa_max.u.v[SIZE-1] = 0x7f;
dwa_min.u.v[SIZE-1] = 0x80;
dwa_1.u.v[0] = 0x01;
}


/* conversion from and to native integers */

/*
Expand Down Expand Up @@ -749,20 +765,26 @@ int main(void)
char *p;
const char *q;

dwa_prep();

puts(dwa_tostru(NULL, dwa_umax, 10)); /* 18446744073709551615 */
puts(dwa_tostr(NULL, dwa_max, 10)); /* 9223372036854775807 */
puts(dwa_tostr(NULL, dwa_min, 10)); /* -9223372036854775808 */

puts(dwa_tostru(NULL, dwa_fromuint(0), 10)); /* 0 */
puts(dwa_tostru(NULL, dwa_fromuint(1), 10)); /* 1 */
puts(dwa_tostru(NULL, dwa_fromuint(0xffffffff), 10)); /* 4294967295 */
puts(dwa_tostru(NULL, dwa_fromuint(-2), 10)); /* 4294967294 */
puts(dwa_tostr(NULL, dwa_fromuint(-2), 10)); /* 4294967294 */
puts(dwa_tostru(NULL, dwa_fromint(0), 10)); /* 0 */
puts(dwa_tostru(NULL, dwa_fromint(-1), 10)); /* 18446744073709551615 */
puts(dwa_tostr(NULL, dwa_fromint(-1), 10)); /* -1 */
puts(dwa_tostr(NULL, dwa_fromint(-2), 10)); /* -2 */
puts(dwa_tostr(NULL, dwa_fromint(-2147483647-1), 10)); /* -2147483648 */
puts(dwa_tostr(NULL, dwa_0, 10)); /* 0 */
puts(dwa_tostr(NULL, dwa_1, 10)); /* 1 */
puts(dwa_tostr(NULL, dwa_neg1, 10)); /* -1 */
puts(dwa_tostru(NULL, dwa_neg1, 10)); /* 18446744073709551615 */

printf("\n%s\n", dwa_tostru(NULL, dwa_fromuint(0), 10)); /* 0 */
puts(dwa_tostru(NULL, dwa_fromuint(1), 10)); /* 1 */
puts(dwa_tostru(NULL, dwa_fromuint(0xffffffff), 10)); /* 4294967295 */
puts(dwa_tostru(NULL, dwa_fromuint(-2), 10)); /* 4294967294 */
puts(dwa_tostr(NULL, dwa_fromuint(-2), 10)); /* 4294967294 */
puts(dwa_tostru(NULL, dwa_fromint(0), 10)); /* 0 */
puts(dwa_tostru(NULL, dwa_fromint(-1), 10)); /* 18446744073709551615 */
puts(dwa_tostr(NULL, dwa_fromint(-1), 10)); /* -1 */
puts(dwa_tostr(NULL, dwa_fromint(-2), 10)); /* -2 */
puts(dwa_tostr(NULL, dwa_fromint(-2147483647-1), 10)); /* -2147483648 */

printf("\n%lu\n", dwa_touint(dwa_fromuint(0))); /* 0 */
printf("%lu\n", dwa_touint(dwa_fromuint(1))); /* 1 */
Expand Down
14 changes: 12 additions & 2 deletions src/cdsl/dwa.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
#define DWA_XOR 1
#define DWA_OR 2

#define DWA_BUFSIZE (1 + sizeof(((dwa_t *)0)->u.v)*8 + 1) /* buffer size for stringization */
#define DWA_WIDTH (sizeof(((dwa_t *)0)->u.v) * 8) /* # of bits in double-word */
#define DWA_BUFSIZE (1 + DWA_WIDTH + 1) /* buffer size for stringization */

#ifndef BASE_TYPE
#define BASE_TYPE long
Expand All @@ -30,8 +31,17 @@ typedef struct dwa_t {


/* min/max values for dwa_t */
const dwa_t dwa_umax, dwa_max, dwa_min;
extern dwa_t dwa_umax;
extern dwa_t dwa_max;
extern dwa_t dwa_min;

/* useful constants */
extern dwa_t dwa_0;
extern dwa_t dwa_1;
extern dwa_t dwa_neg1;


void dwa_prep(void);

/* conversion from and to native integers */
dwa_t dwa_fromuint(dwa_ubase_t);
Expand Down

0 comments on commit ed4c9b2

Please sign in to comment.