diff options
author | chmod222 <304922+chmod222@users.noreply.github.com> | 2023-04-03 05:22:31 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-03 05:22:31 +0200 |
commit | 31d3606fe82855dc63cb59fa509577ba1c3a3b86 (patch) | |
tree | f86f0ddfaa11f439fd85fe76074a904548b2e12b /lib/pure/bitops.nim | |
parent | 6ec9c7f683abd520ad70b7ca6fbee11312b5cf11 (diff) | |
download | Nim-31d3606fe82855dc63cb59fa509577ba1c3a3b86.tar.gz |
fixes #21564; std/bitops: Add explicit type masking for the JS target (#21598)
* std/bitops: Add explicit type masking for the JS target Typecasts on the JavaScript backend do not function the same way as they do on C and C++ backends, so for bitwise operations we may need to mask them back down into their allowed range when they get shifted outside it. Since they do work as expected on the other backends, a default bitmask of all 1's is casted down into the target type as an easily optimizable "& 0xFF" operation for these backends. * Fixup: this should still be a func * Run test case on js target * Adapt testcase to contributor guide and best practices * Simplify constrain logic and turn into actual no-op for the C side
Diffstat (limited to 'lib/pure/bitops.nim')
-rw-r--r-- | lib/pure/bitops.nim | 12 |
1 files changed, 9 insertions, 3 deletions
diff --git a/lib/pure/bitops.nim b/lib/pure/bitops.nim index a518c25d2..d19c3d248 100644 --- a/lib/pure/bitops.nim +++ b/lib/pure/bitops.nim @@ -63,6 +63,12 @@ macro bitxor*[T: SomeInteger](x, y: T; z: varargs[T]): T = type BitsRange*[T] = range[0..sizeof(T)*8-1] ## A range with all bit positions for type `T`. +template typeMasked[T: SomeInteger](x: T): T = + when defined(js): + x and ((0xffffffff_ffffffff'u shr (64 - sizeof(T) * 8))) + else: + x + func bitsliced*[T: SomeInteger](v: T; slice: Slice[int]): T {.inline, since: (1, 3).} = ## Returns an extracted (and shifted) slice of bits from `v`. runnableExamples: @@ -73,7 +79,7 @@ func bitsliced*[T: SomeInteger](v: T; slice: Slice[int]): T {.inline, since: (1, let upmost = sizeof(T) * 8 - 1 uv = v.castToUnsigned - (uv shl (upmost - slice.b) shr (upmost - slice.b + slice.a)).T + ((uv shl (upmost - slice.b)).typeMasked shr (upmost - slice.b + slice.a)).T proc bitslice*[T: SomeInteger](v: var T; slice: Slice[int]) {.inline, since: (1, 3).} = ## Mutates `v` into an extracted (and shifted) slice of bits from `v`. @@ -85,7 +91,7 @@ proc bitslice*[T: SomeInteger](v: var T; slice: Slice[int]) {.inline, since: (1, let upmost = sizeof(T) * 8 - 1 uv = v.castToUnsigned - v = (uv shl (upmost - slice.b) shr (upmost - slice.b + slice.a)).T + v = ((uv shl (upmost - slice.b)).typeMasked shr (upmost - slice.b + slice.a)).T func toMask*[T: SomeInteger](slice: Slice[int]): T {.inline, since: (1, 3).} = ## Creates a bitmask based on a slice of bits. @@ -96,7 +102,7 @@ func toMask*[T: SomeInteger](slice: Slice[int]): T {.inline, since: (1, 3).} = let upmost = sizeof(T) * 8 - 1 bitmask = bitnot(0.T).castToUnsigned - (bitmask shl (upmost - slice.b + slice.a) shr (upmost - slice.b)).T + ((bitmask shl (upmost - slice.b + slice.a)).typeMasked shr (upmost - slice.b)).T proc masked*[T: SomeInteger](v, mask :T): T {.inline, since: (1, 3).} = ## Returns `v`, with only the `1` bits from `mask` matching those of |