Skip to content

Commit 23006df

Browse files
authored
implement card (#825)
* implement `card` * update test
1 parent 4b1b520 commit 23006df

File tree

6 files changed

+368
-62
lines changed

6 files changed

+368
-62
lines changed

lib/std/system.nim

+1
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,7 @@ template len*[I, T](x: array[I, T]): int =
471471
# is the string equality is used by hexer/stringcases.nim.
472472
include "system/stringimpl"
473473

474+
include "system/countbits_impl"
474475
include "system/setops"
475476

476477
include "system/openarrays"

lib/std/system/countbits_impl.nim

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# slightly modified from original countbits_impl
2+
3+
# C compiler defines seem to not be defined yet:
4+
const useBuiltins = not defined(noIntrinsicsBitOpts)
5+
const useGCC_builtins = (defined(gcc) or defined(llvm_gcc) or
6+
defined(clang)) and useBuiltins
7+
const useICC_builtins = defined(icc) and useBuiltins
8+
const useVCC_builtins = defined(vcc) and useBuiltins
9+
const arch64 = true # sizeof(int) == 8
10+
11+
template countBitsImpl(n: uint32): int =
12+
# generic formula is from: https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
13+
var v = uint32(n)
14+
v = v - ((v shr 1) and 0x55555555'u32)
15+
v = (v and 0x33333333'u32) + ((v shr 2) and 0x33333333'u32)
16+
(((v + (v shr 4) and 0xF0F0F0F'u32) * 0x1010101'u32) shr 24).int
17+
18+
template countBitsImpl(n: uint64): int =
19+
# generic formula is from: https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
20+
var v = uint64(n)
21+
v = v - ((v shr 1) and 0x5555555555555555'u64)
22+
v = (v and 0x3333333333333333'u64) + ((v shr 2) and 0x3333333333333333'u64)
23+
v = (v + (v shr 4) and 0x0F0F0F0F0F0F0F0F'u64)
24+
((v * 0x0101010101010101'u64) shr 56).int
25+
26+
27+
when useGCC_builtins:
28+
# Returns the number of set 1-bits in value.
29+
proc builtin_popcount(x: cuint): cint {.importc: "__builtin_popcount", cdecl.}
30+
proc builtin_popcountll(x: culonglong): cint {.
31+
importc: "__builtin_popcountll", cdecl.}
32+
33+
elif useVCC_builtins:
34+
# Counts the number of one bits (population count) in a 16-, 32-, or 64-byte unsigned integer.
35+
func builtin_popcnt16(a2: uint16): uint16 {.
36+
importc: "__popcnt16", header: "<intrin.h>".}
37+
func builtin_popcnt32(a2: uint32): uint32 {.
38+
importc: "__popcnt", header: "<intrin.h>".}
39+
func builtin_popcnt64(a2: uint64): uint64 {.
40+
importc: "__popcnt64", header: "<intrin.h>".}
41+
42+
elif useICC_builtins:
43+
# Intel compiler intrinsics: http://fulla.fnal.gov/intel/compiler_c/main_cls/intref_cls/common/intref_allia_misc.htm
44+
# see also: https://software.intel.com/en-us/node/523362
45+
# Count the number of bits set to 1 in an integer a, and return that count in dst.
46+
func builtin_popcnt32(a: cint): cint {.
47+
importc: "_popcnt", header: "<immintrin.h>".}
48+
func builtin_popcnt64(a: uint64): cint {.
49+
importc: "_popcnt64", header: "<immintrin.h>".}
50+
51+
proc countBits32*(x: uint32): int {.inline.} =
52+
when useGCC_builtins:
53+
result = builtin_popcount(x.cuint).int
54+
elif useVCC_builtins:
55+
result = builtin_popcnt32(x.uint32).int
56+
elif useICC_builtins:
57+
result = builtin_popcnt32(x.cint).int
58+
else:
59+
result = countBitsImpl(x.uint32)
60+
61+
proc countBits64*(x: uint64): int {.inline.} =
62+
when useGCC_builtins:
63+
result = builtin_popcountll(x.culonglong).int
64+
elif useVCC_builtins:
65+
when arch64: result = builtin_popcnt64(x.uint64).int
66+
else: result = builtin_popcnt32((x.uint64 and 0xFFFFFFFF'u64).uint32).int +
67+
builtin_popcnt32((x.uint64 shr 32'u64).uint32).int
68+
elif useICC_builtins:
69+
when arch64: result = builtin_popcnt64(x.uint64).int
70+
else: result = builtin_popcnt32((x.uint64 and 0xFFFFFFFF'u64).cint).int +
71+
builtin_popcnt32((x.uint64 shr 32'u64).cint).int
72+
else:
73+
result = countBitsImpl(x.uint64)

lib/std/system/setops.nim

+17
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,20 @@ func `+`*[T](x, y: set[T]): set[T] {.magic: "PlusSet".}
2222
func `-`*[T](x, y: set[T]): set[T] {.magic: "MinusSet".}
2323

2424
func contains*[T](x: set[T], y: T): bool {.magic: "InSet".}
25+
26+
proc cardSetImpl(s: ptr UncheckedArray[uint8], len: int): int {.inline.} =
27+
var i = 0
28+
result = 0
29+
var num = 0'u64
30+
when defined(x86) or defined(amd64):
31+
while i < len - 8:
32+
copyMem(addr num, addr s[i], 8)
33+
inc(result, countBits64(num))
34+
inc(i, 8)
35+
36+
while i < len:
37+
inc(result, countBits32(uint32(s[i])))
38+
inc(i, 1)
39+
40+
proc cardSet(s: ptr UncheckedArray[uint8], len: int): int {.inline.} =
41+
result = cardSetImpl(s, len)

src/hexer/desugar.nim

+42-7
Original file line numberDiff line numberDiff line change
@@ -225,9 +225,6 @@ proc genSetOp(c: var Context; dest: var TokenBuf; n: var Cursor) =
225225
case size
226226
of 1, 2, 4, 8:
227227
case kind
228-
of CardX:
229-
# XXX needs countBits compilerproc
230-
raiseAssert("unimplemented")
231228
of LtSetX:
232229
copyIntoKind dest, AndX, info:
233230
addTypedOp dest, EqX, cType, info:
@@ -283,9 +280,6 @@ proc genSetOp(c: var Context; dest: var TokenBuf; n: var Cursor) =
283280
raiseAssert("unreachable")
284281
else:
285282
case kind
286-
of CardX:
287-
# XXX originally implemented as cardSet compilerproc
288-
raiseAssert("unimplemented")
289283
of LtSetX, LeSetX:
290284
dest.add parLeToken(ExprX, info)
291285
let resValue = [parLeToken(TrueX, info), parRiToken(info)]
@@ -388,6 +382,45 @@ proc genSetOp(c: var Context; dest: var TokenBuf; n: var Cursor) =
388382
dest.addParRi()
389383
c.tempUseBufStack.shrink(oldBufStackLen)
390384

385+
proc genCard(c: var Context; dest: var TokenBuf; n: var Cursor) =
386+
let info = n.info
387+
inc n
388+
let typ = n
389+
if typ.typeKind != SetT:
390+
error "expected set type for set op", n
391+
var baseType = typ
392+
inc baseType
393+
var argsBuf = createTokenBuf(16)
394+
swap dest, argsBuf
395+
skip n # nothing to do with set type
396+
let aStart = dest.len
397+
tr(c, dest, n)
398+
swap dest, argsBuf
399+
skipParRi n
400+
let a = cursorAt(argsBuf, aStart) # no temp needed
401+
var err = false
402+
let size = asSigned(bitsetSizeInBytes(baseType), err)
403+
assert not err
404+
case size
405+
of 1, 2:
406+
copyIntoKind dest, CallX, info:
407+
dest.add symToken(pool.syms.getOrIncl("countBits32.0." & SystemModuleSuffix), info)
408+
addUIntTypedOp dest, CastX, 32, info:
409+
dest.addSubtree a
410+
of 4:
411+
copyIntoKind dest, CallX, info:
412+
dest.add symToken(pool.syms.getOrIncl("countBits32.0." & SystemModuleSuffix), info)
413+
dest.addSubtree a
414+
of 8:
415+
copyIntoKind dest, CallX, info:
416+
dest.add symToken(pool.syms.getOrIncl("countBits64.0." & SystemModuleSuffix), info)
417+
dest.addSubtree a
418+
else:
419+
copyIntoKind dest, CallX, info:
420+
dest.add symToken(pool.syms.getOrIncl("cardSet.0." & SystemModuleSuffix), info)
421+
dest.arrayToPointer(a, info)
422+
dest.addIntLit(size, info)
423+
391424
proc genSingleInclSmall(dest: var TokenBuf; s, elem: Cursor; size: int; info: PackedLineInfo) =
392425
let bits = size * 8
393426
copyIntoKind dest, AsgnS, info:
@@ -673,8 +706,10 @@ proc tr(c: var Context; dest: var TokenBuf; n: var Cursor) =
673706
trSons(c, dest, n)
674707
of SetConstrX:
675708
genSetConstr(c, dest, n)
676-
of PlusSetX, MinusSetX, MulSetX, XorSetX, EqSetX, LeSetX, LtSetX, InSetX, CardX:
709+
of PlusSetX, MinusSetX, MulSetX, XorSetX, EqSetX, LeSetX, LtSetX, InSetX:
677710
genSetOp(c, dest, n)
711+
of CardX:
712+
genCard(c, dest, n)
678713
of TypeofX:
679714
takeTree dest, n
680715
of DdotX:

0 commit comments

Comments
 (0)