Vm bitops fixes (#10520)
This commit is contained in:
parent
bcb5995ddf
commit
824f39b32e
5 changed files with 47 additions and 62 deletions
|
|
@ -1264,6 +1264,11 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
of opcNarrowU:
|
of opcNarrowU:
|
||||||
decodeB(rkInt)
|
decodeB(rkInt)
|
||||||
regs[ra].intVal = regs[ra].intVal and ((1'i64 shl rb)-1)
|
regs[ra].intVal = regs[ra].intVal and ((1'i64 shl rb)-1)
|
||||||
|
of opcSignExtend:
|
||||||
|
# like opcNarrowS, but no out of range possible
|
||||||
|
decodeB(rkInt)
|
||||||
|
let imm = 64 - rb
|
||||||
|
regs[ra].intVal = ashr(regs[ra].intVal shl imm, imm)
|
||||||
of opcIsNil:
|
of opcIsNil:
|
||||||
decodeB(rkInt)
|
decodeB(rkInt)
|
||||||
let node = regs[rb].node
|
let node = regs[rb].node
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,7 @@ type
|
||||||
opcSubStr, opcParseFloat, opcConv, opcCast,
|
opcSubStr, opcParseFloat, opcConv, opcCast,
|
||||||
opcQuit,
|
opcQuit,
|
||||||
opcNarrowS, opcNarrowU,
|
opcNarrowS, opcNarrowU,
|
||||||
|
opcSignExtend,
|
||||||
|
|
||||||
opcAddStrCh,
|
opcAddStrCh,
|
||||||
opcAddStrStr,
|
opcAddStrStr,
|
||||||
|
|
|
||||||
|
|
@ -986,7 +986,14 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||||
c.freeTemp(tmp)
|
c.freeTemp(tmp)
|
||||||
c.freeTemp(tmp2)
|
c.freeTemp(tmp2)
|
||||||
|
|
||||||
of mShlI: genBinaryABCnarrowU(c, n, dest, opcShlInt)
|
of mShlI:
|
||||||
|
genBinaryABC(c, n, dest, opcShlInt)
|
||||||
|
# genNarrowU modified
|
||||||
|
let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
|
||||||
|
if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and t.size < 8):
|
||||||
|
c.gABC(n, opcNarrowU, dest, TRegister(t.size*8))
|
||||||
|
elif t.kind in {tyInt8..tyInt32} or (t.kind == tyInt and t.size < 8):
|
||||||
|
c.gABC(n, opcSignExtend, dest, TRegister(t.size*8))
|
||||||
of mAshrI: genBinaryABC(c, n, dest, opcAshrInt)
|
of mAshrI: genBinaryABC(c, n, dest, opcAshrInt)
|
||||||
of mBitandI: genBinaryABC(c, n, dest, opcBitandInt)
|
of mBitandI: genBinaryABC(c, n, dest, opcBitandInt)
|
||||||
of mBitorI: genBinaryABC(c, n, dest, opcBitorInt)
|
of mBitorI: genBinaryABC(c, n, dest, opcBitorInt)
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,18 @@ const useICC_builtins = defined(icc) and useBuiltins
|
||||||
const useVCC_builtins = defined(vcc) and useBuiltins
|
const useVCC_builtins = defined(vcc) and useBuiltins
|
||||||
const arch64 = sizeof(int) == 8
|
const arch64 = sizeof(int) == 8
|
||||||
|
|
||||||
|
template forwardImpl(impl, arg) {.dirty.} =
|
||||||
|
when sizeof(x) <= 4:
|
||||||
|
when x is SomeSignedInt:
|
||||||
|
impl(cast[uint32](x.int32))
|
||||||
|
else:
|
||||||
|
impl(x.uint32)
|
||||||
|
else:
|
||||||
|
when x is SomeSignedInt:
|
||||||
|
impl(cast[uint64](x.int64))
|
||||||
|
else:
|
||||||
|
impl(x.uint64)
|
||||||
|
|
||||||
when defined(nimHasalignOf):
|
when defined(nimHasalignOf):
|
||||||
|
|
||||||
import macros
|
import macros
|
||||||
|
|
@ -243,8 +255,7 @@ proc countSetBits*(x: SomeInteger): int {.inline, nosideeffect.} =
|
||||||
# TODO: figure out if ICC support _popcnt32/_popcnt64 on platform without POPCNT.
|
# TODO: figure out if ICC support _popcnt32/_popcnt64 on platform without POPCNT.
|
||||||
# like GCC and MSVC
|
# like GCC and MSVC
|
||||||
when nimvm:
|
when nimvm:
|
||||||
when sizeof(x) <= 4: result = countSetBits_nim(x.uint32)
|
result = forwardImpl(countSetBits_nim, x)
|
||||||
else: result = countSetBits_nim(x.uint64)
|
|
||||||
else:
|
else:
|
||||||
when useGCC_builtins:
|
when useGCC_builtins:
|
||||||
when sizeof(x) <= 4: result = builtin_popcount(x.cuint).int
|
when sizeof(x) <= 4: result = builtin_popcount(x.cuint).int
|
||||||
|
|
@ -274,8 +285,7 @@ proc parityBits*(x: SomeInteger): int {.inline, nosideeffect.} =
|
||||||
# Can be used a base if creating ASM version.
|
# Can be used a base if creating ASM version.
|
||||||
# https://stackoverflow.com/questions/21617970/how-to-check-if-value-has-even-parity-of-bits-or-odd
|
# https://stackoverflow.com/questions/21617970/how-to-check-if-value-has-even-parity-of-bits-or-odd
|
||||||
when nimvm:
|
when nimvm:
|
||||||
when sizeof(x) <= 4: result = parity_impl(x.uint32)
|
result = forwardImpl(parity_impl, x)
|
||||||
else: result = parity_impl(x.uint64)
|
|
||||||
else:
|
else:
|
||||||
when useGCC_builtins:
|
when useGCC_builtins:
|
||||||
when sizeof(x) <= 4: result = builtin_parity(x.uint32).int
|
when sizeof(x) <= 4: result = builtin_parity(x.uint32).int
|
||||||
|
|
@ -293,8 +303,7 @@ proc firstSetBit*(x: SomeInteger): int {.inline, nosideeffect.} =
|
||||||
when noUndefined:
|
when noUndefined:
|
||||||
if x == 0:
|
if x == 0:
|
||||||
return 0
|
return 0
|
||||||
when sizeof(x) <= 4: result = firstSetBit_nim(x.uint32)
|
result = forwardImpl(firstSetBit_nim, x)
|
||||||
else: result = firstSetBit_nim(x.uint64)
|
|
||||||
else:
|
else:
|
||||||
when noUndefined and not useGCC_builtins:
|
when noUndefined and not useGCC_builtins:
|
||||||
if x == 0:
|
if x == 0:
|
||||||
|
|
@ -328,8 +337,7 @@ proc fastLog2*(x: SomeInteger): int {.inline, nosideeffect.} =
|
||||||
if x == 0:
|
if x == 0:
|
||||||
return -1
|
return -1
|
||||||
when nimvm:
|
when nimvm:
|
||||||
when sizeof(x) <= 4: result = fastlog2_nim(x.uint32)
|
result = forwardImpl(fastlog2_nim, x)
|
||||||
else: result = fastlog2_nim(x.uint64)
|
|
||||||
else:
|
else:
|
||||||
when useGCC_builtins:
|
when useGCC_builtins:
|
||||||
when sizeof(x) <= 4: result = 31 - builtin_clz(x.uint32).int
|
when sizeof(x) <= 4: result = 31 - builtin_clz(x.uint32).int
|
||||||
|
|
@ -360,8 +368,7 @@ proc countLeadingZeroBits*(x: SomeInteger): int {.inline, nosideeffect.} =
|
||||||
if x == 0:
|
if x == 0:
|
||||||
return 0
|
return 0
|
||||||
when nimvm:
|
when nimvm:
|
||||||
when sizeof(x) <= 4: result = sizeof(x)*8 - 1 - fastlog2_nim(x.uint32)
|
result = sizeof(x)*8 - 1 - forwardImpl(fastlog2_nim, x)
|
||||||
else: result = sizeof(x)*8 - 1 - fastlog2_nim(x.uint64)
|
|
||||||
else:
|
else:
|
||||||
when useGCC_builtins:
|
when useGCC_builtins:
|
||||||
when sizeof(x) <= 4: result = builtin_clz(x.uint32).int - (32 - sizeof(x)*8)
|
when sizeof(x) <= 4: result = builtin_clz(x.uint32).int - (32 - sizeof(x)*8)
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
discard """
|
discard """
|
||||||
|
nimout: "OK"
|
||||||
output: "OK"
|
output: "OK"
|
||||||
"""
|
"""
|
||||||
import bitops
|
import bitops
|
||||||
|
|
||||||
|
|
||||||
proc main() =
|
proc main() =
|
||||||
const U8 = 0b0011_0010'u8
|
const U8 = 0b0011_0010'u8
|
||||||
const I8 = 0b0011_0010'i8
|
const I8 = 0b0011_0010'i8
|
||||||
|
|
@ -79,25 +79,6 @@ proc main() =
|
||||||
doAssert( U8.rotateLeftBits(3) == 0b10010001'u8)
|
doAssert( U8.rotateLeftBits(3) == 0b10010001'u8)
|
||||||
doAssert( U8.rotateRightBits(3) == 0b0100_0110'u8)
|
doAssert( U8.rotateRightBits(3) == 0b0100_0110'u8)
|
||||||
|
|
||||||
static :
|
|
||||||
# test bitopts at compile time with vm
|
|
||||||
doAssert( U8.fastLog2 == 5)
|
|
||||||
doAssert( I8.fastLog2 == 5)
|
|
||||||
doAssert( U8.countLeadingZeroBits == 2)
|
|
||||||
doAssert( I8.countLeadingZeroBits == 2)
|
|
||||||
doAssert( U8.countTrailingZeroBits == 1)
|
|
||||||
doAssert( I8.countTrailingZeroBits == 1)
|
|
||||||
doAssert( U8.firstSetBit == 2)
|
|
||||||
doAssert( I8.firstSetBit == 2)
|
|
||||||
doAssert( U8.parityBits == 1)
|
|
||||||
doAssert( I8.parityBits == 1)
|
|
||||||
doAssert( U8.countSetBits == 3)
|
|
||||||
doAssert( I8.countSetBits == 3)
|
|
||||||
doAssert( U8.rotateLeftBits(3) == 0b10010001'u8)
|
|
||||||
doAssert( U8.rotateRightBits(3) == 0b0100_0110'u8)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template test_undefined_impl(ffunc: untyped; expected: int; is_static: bool) =
|
template test_undefined_impl(ffunc: untyped; expected: int; is_static: bool) =
|
||||||
doAssert( ffunc(0'u8) == expected)
|
doAssert( ffunc(0'u8) == expected)
|
||||||
doAssert( ffunc(0'i8) == expected)
|
doAssert( ffunc(0'i8) == expected)
|
||||||
|
|
@ -142,26 +123,6 @@ proc main() =
|
||||||
doAssert( U64A.rotateLeftBits(64) == U64A)
|
doAssert( U64A.rotateLeftBits(64) == U64A)
|
||||||
doAssert( U64A.rotateRightBits(64) == U64A)
|
doAssert( U64A.rotateRightBits(64) == U64A)
|
||||||
|
|
||||||
static: # check for undefined behavior with rotate by zero.
|
|
||||||
doAssert( U8.rotateLeftBits(0) == U8)
|
|
||||||
doAssert( U8.rotateRightBits(0) == U8)
|
|
||||||
doAssert( U16.rotateLeftBits(0) == U16)
|
|
||||||
doAssert( U16.rotateRightBits(0) == U16)
|
|
||||||
doAssert( U32.rotateLeftBits(0) == U32)
|
|
||||||
doAssert( U32.rotateRightBits(0) == U32)
|
|
||||||
doAssert( U64A.rotateLeftBits(0) == U64A)
|
|
||||||
doAssert( U64A.rotateRightBits(0) == U64A)
|
|
||||||
|
|
||||||
# check for undefined behavior with rotate by integer width.
|
|
||||||
doAssert( U8.rotateLeftBits(8) == U8)
|
|
||||||
doAssert( U8.rotateRightBits(8) == U8)
|
|
||||||
doAssert( U16.rotateLeftBits(16) == U16)
|
|
||||||
doAssert( U16.rotateRightBits(16) == U16)
|
|
||||||
doAssert( U32.rotateLeftBits(32) == U32)
|
|
||||||
doAssert( U32.rotateRightBits(32) == U32)
|
|
||||||
doAssert( U64A.rotateLeftBits(64) == U64A)
|
|
||||||
doAssert( U64A.rotateRightBits(64) == U64A)
|
|
||||||
|
|
||||||
block:
|
block:
|
||||||
# mask operations
|
# mask operations
|
||||||
var v: uint8
|
var v: uint8
|
||||||
|
|
@ -207,8 +168,10 @@ proc main() =
|
||||||
var v: uint64
|
var v: uint64
|
||||||
v.setBit(63)
|
v.setBit(63)
|
||||||
doAssert v == 0b1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000'u64
|
doAssert v == 0b1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000'u64
|
||||||
block:
|
|
||||||
# Test if RangeError is thrown if indexing out of range
|
echo "OK"
|
||||||
|
|
||||||
|
block: # not ready for vm because exception is compile error
|
||||||
try:
|
try:
|
||||||
var v: uint32
|
var v: uint32
|
||||||
var i = 32
|
var i = 32
|
||||||
|
|
@ -219,6 +182,8 @@ proc main() =
|
||||||
except:
|
except:
|
||||||
doAssert false
|
doAssert false
|
||||||
|
|
||||||
echo "OK"
|
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
static:
|
||||||
|
# test everything on vm as well
|
||||||
|
main()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue