mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-19 05:50:30 +00:00
* 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
This commit is contained in:
@@ -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
|
||||
|
||||
28
tests/stdlib/t21564.nim
Normal file
28
tests/stdlib/t21564.nim
Normal file
@@ -0,0 +1,28 @@
|
||||
discard """
|
||||
targets: "c js"
|
||||
"""
|
||||
|
||||
import bitops
|
||||
import std/assertions
|
||||
|
||||
proc main() =
|
||||
block: # bug #21564
|
||||
# tesk `bitops.bitsliced` patch
|
||||
doAssert(0x17.bitsliced(4..7) == 0x01)
|
||||
doAssert(0x17.bitsliced(0..3) == 0x07)
|
||||
|
||||
block:
|
||||
# test in-place `bitops.bitslice`
|
||||
var t = 0x12F4
|
||||
t.bitslice(4..7)
|
||||
|
||||
doAssert(t == 0xF)
|
||||
|
||||
block:
|
||||
# test `bitops.toMask` patch via bitops.masked
|
||||
doAssert(0x12FFFF34.masked(8..23) == 0x00FFFF00)
|
||||
|
||||
main()
|
||||
|
||||
static:
|
||||
main()
|
||||
Reference in New Issue
Block a user