Skip to content

Commit 62f5475

Browse files
committed
wip: bitop tests and using hamt with bitops
1 parent 880f4a0 commit 62f5475

File tree

10 files changed

+250
-32
lines changed

10 files changed

+250
-32
lines changed

CLAUDE.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ The runtime implements:
124124

125125
## Testing Strategy
126126

127+
127128
Tests are organized in `/tests/`, with the following subfolders
128129

129130
- `cmp` - Negative compiler tests.
@@ -137,6 +138,11 @@ Tests are organized in `/tests/`, with the following subfolders
137138
- `warn/` - Tests that should produce warnings
138139
- `multinode/` - Multinode (networking) tests
139140

141+
142+
## Creating new tests
143+
144+
Do not put tests into the folders with existing .golden files, without explicit permission!
145+
140146
### Testing non-networking functionality
141147

142148
Non-network tests have a `.trp` source file and a `.golden` file with expected output. The comparison of the expected output is handled using the golden utility. This is needed because outputs often include timestamped value and that utility invokes the special diff that discards the timestamps.

lib/hamt.trp

Lines changed: 13 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
(* Hash Array Mapped Trie (HAMT) library for Troupe *)
1+
(* Hash Array Mapped Trie (HAMT) library for Troupe - Optimized with native bit operations *)
22

3-
(* 2025-07-29: Note; AA -- this is currently very slow --
4-
so it is a good target for driving the performance tuning
5-
*)
3+
(* 2025-07-29: Updated to use native bit operations instead of arithmetic simulation *)
64

75
import lists
86

@@ -15,20 +13,6 @@ let
1513
val BRANCH_FACTOR = 32 (* 2^5 branches *)
1614
val MASK = 31 (* 0b11111 *)
1715

18-
(* Integer power function *)
19-
fun intPow base exp =
20-
if exp = 0 then 1
21-
else base * intPow base (exp - 1)
22-
23-
(* String length helper *)
24-
(* fun strLen s =
25-
let fun len s idx =
26-
case (substring (s, idx, 1)) of
27-
"" => idx
28-
| _ => len s (idx + 1)
29-
in len s 0
30-
end
31-
*)
3216
(* Character code at index - extended character set *)
3317
fun charCode s idx = charCodeAtWithDefault (s, idx, 63)
3418

@@ -53,29 +37,26 @@ let
5337
end
5438
end
5539

56-
(* Get the index at a given level from hash *)
57-
fun getIndex hashval level = (hashval div (intPow BRANCH_FACTOR level)) mod BRANCH_FACTOR
40+
(* Get the index at a given level from hash - using bit operations *)
41+
fun getIndex hashval level = (hashval >> (level * SHIFT)) andb MASK
5842

59-
(* Bitmap operations simulated with arithmetic *)
60-
fun setBit bitmap pos = bitmap + intPow 2 pos
61-
fun testBit bitmap pos = ((bitmap div (intPow 2 pos)) mod 2) = 1
62-
fun clearBit bitmap pos =
63-
if testBit bitmap pos
64-
then bitmap - intPow 2 pos
65-
else bitmap
43+
(* Bitmap operations using native bit operations *)
44+
fun setBit bitmap pos = bitmap orb (1 << pos)
45+
fun testBit bitmap pos = ((bitmap >> pos) andb 1) = 1
46+
fun clearBit bitmap pos = bitmap andb ((-1) xorb (1 << pos))
6647

6748
fun popcount bitmap =
6849
let fun count bm acc =
6950
if bm = 0 then acc
70-
else count (bm div 2) (acc + (bm mod 2))
51+
else count (bm >> 1) (acc + (bm andb 1))
7152
in count bitmap 0
7253
end
7354

7455
fun positionInBitmap bitmap pos =
75-
let fun countBits bm p acc =
76-
if p = 0 then acc
77-
else countBits (bm div 2) (p - 1) (acc + (bm mod 2))
78-
in countBits bitmap pos 0
56+
(* Count the number of 1 bits before position pos *)
57+
let val mask = (1 << pos) - 1
58+
val masked = bitmap andb mask
59+
in popcount masked
7960
end
8061

8162
(* Array operations using lists *)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
2025-07-29T08:43:00.734Z [RTM] info: Skipping network creation. Observe that all external IO operations will yield a runtime error.
2+
("Lookup 'hello':"@{}%{}, (SOME@{}%{}, 1@{}%{})@{}%{})@{}%{}
3+
("Lookup 'world':"@{}%{}, (SOME@{}%{}, 2@{}%{})@{}%{})@{}%{}
4+
("Lookup 42:"@{}%{}, (SOME@{}%{}, "number key"@{}%{})@{}%{})@{}%{}
5+
("Size:"@{}%{}, 3@{}%{})@{}%{}
6+
("Updated 'hello':"@{}%{}, (SOME@{}%{}, 10@{}%{})@{}%{})@{}%{}
7+
("After removing 'world':"@{}%{}, NONE@{}%{})@{}%{}
8+
("Size after remove:"@{}%{}, 2@{}%{})@{}%{}
9+
("Big trie size:"@{}%{}, 30@{}%{})@{}%{}
10+
("Lookup '15':"@{}%{}, (SOME@{}%{}, 15@{}%{})@{}%{})@{}%{}
11+
("Lookup '30':"@{}%{}, (SOME@{}%{}, 30@{}%{})@{}%{})@{}%{}
12+
"Bit operation verification:"@{}%{}
13+
("15 andb 7 ="@{}%{}, 7@{}%{})@{}%{}
14+
("8 orb 4 ="@{}%{}, 12@{}%{})@{}%{}
15+
("15 xorb 10 ="@{}%{}, 5@{}%{})@{}%{}
16+
("1 << 5 ="@{}%{}, 32@{}%{})@{}%{}
17+
("32 >> 3 ="@{}%{}, 4@{}%{})@{}%{}
18+
"Optimized HAMT test completed!"@{}%{}
19+
>>> Main thread finished with value: ()@{}%{}

tests/rt/hamt-tests/hamt-test.trp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
(* Test HAMT library with native bit operations *)
2+
import hamt
3+
4+
let
5+
(* Create an empty HAMT *)
6+
val empty_trie = empty ()
7+
8+
(* Basic insertion and lookup *)
9+
val t1 = insert empty_trie "hello" 1
10+
val t2 = insert t1 "world" 2
11+
val t3 = insert t2 42 "number key"
12+
13+
val _ = printWithLabels ("Lookup 'hello':", lookup t3 "hello")
14+
val _ = printWithLabels ("Lookup 'world':", lookup t3 "world")
15+
val _ = printWithLabels ("Lookup 42:", lookup t3 42)
16+
val _ = printWithLabels ("Size:", size t3)
17+
18+
(* Test updates *)
19+
val t4 = insert t3 "hello" 10
20+
val _ = printWithLabels ("Updated 'hello':", lookup t4 "hello")
21+
22+
(* Test removal *)
23+
val t5 = remove t4 "world"
24+
val _ = printWithLabels ("After removing 'world':", lookup t5 "world")
25+
val _ = printWithLabels ("Size after remove:", size t5)
26+
27+
(* Test with many entries *)
28+
val bigTrie =
29+
let fun makeList n acc =
30+
if n = 0 then acc
31+
else makeList (n - 1) ((intToString n, n) :: acc)
32+
in fromList (makeList 30 [])
33+
end
34+
val _ = printWithLabels ("Big trie size:", size bigTrie)
35+
val _ = printWithLabels ("Lookup '15':", lookup bigTrie "15")
36+
val _ = printWithLabels ("Lookup '30':", lookup bigTrie "30")
37+
38+
(* Verify bit operations are working *)
39+
val _ = printWithLabels "Bit operation verification:"
40+
val _ = printWithLabels ("15 andb 7 =", 15 andb 7)
41+
val _ = printWithLabels ("8 orb 4 =", 8 orb 4)
42+
val _ = printWithLabels ("15 xorb 10 =", 15 xorb 10)
43+
val _ = printWithLabels ("1 << 5 =", 1 << 5)
44+
val _ = printWithLabels ("32 >> 3 =", 32 >> 3)
45+
46+
in printWithLabels "Optimized HAMT test completed!"
47+
end
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
2025-07-29T00:49:05.566Z [RTM] info: Skipping network creation. Observe that all external IO operations will yield a runtime error.
2+
"Testing edge cases..."@{}%{}
3+
"Negative numbers:"@{}%{}
4+
("-1 andb 255 ="@{}%{}, 255@{}%{})@{}%{}
5+
("-1 orb 0 ="@{}%{}, -1@{}%{})@{}%{}
6+
("-1 xorb -1 ="@{}%{}, 0@{}%{})@{}%{}
7+
"32-bit boundaries:"@{}%{}
8+
("2147483647 << 1 ="@{}%{}, -2@{}%{})@{}%{}
9+
("-2147483648 >> 1 ="@{}%{}, -1073741824@{}%{})@{}%{}
10+
("-1 ~>> 1 ="@{}%{}, 2147483647@{}%{})@{}%{}
11+
"Operations with zero:"@{}%{}
12+
("0 andb 0 ="@{}%{}, 0@{}%{})@{}%{}
13+
("0 orb 0 ="@{}%{}, 0@{}%{})@{}%{}
14+
("0 xorb 0 ="@{}%{}, 0@{}%{})@{}%{}
15+
("0 << 10 ="@{}%{}, 0@{}%{})@{}%{}
16+
("0 >> 10 ="@{}%{}, 0@{}%{})@{}%{}
17+
"Large shift amounts:"@{}%{}
18+
("1 << 31 ="@{}%{}, -2147483648@{}%{})@{}%{}
19+
("1 << 32 ="@{}%{}, 1@{}%{})@{}%{}
20+
("-2147483648 >> 31 ="@{}%{}, -1@{}%{})@{}%{}
21+
("-2147483648 ~>> 31 ="@{}%{}, 1@{}%{})@{}%{}
22+
"Edge case tests completed!"@{}%{}
23+
>>> Main thread finished with value: ()@{}%{}

tests/rt/pos/core/bitops-edge.trp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
(* Test edge cases for bit operations *)
2+
let val _ = printWithLabels ("Testing edge cases...")
3+
4+
(* Test with negative numbers *)
5+
val _ = printWithLabels ("Negative numbers:")
6+
val _ = printWithLabels ("-1 andb 255 =", (-1) andb 255)
7+
val _ = printWithLabels ("-1 orb 0 =", (-1) orb 0)
8+
val _ = printWithLabels ("-1 xorb -1 =", (-1) xorb (-1))
9+
10+
(* Test with 32-bit boundaries *)
11+
val _ = printWithLabels ("32-bit boundaries:")
12+
val _ = printWithLabels ("2147483647 << 1 =", 2147483647 << 1)
13+
val _ = printWithLabels ("-2147483648 >> 1 =", (-2147483648) >> 1)
14+
val _ = printWithLabels ("-1 ~>> 1 =", (-1) ~>> 1)
15+
16+
(* Test with zeros *)
17+
val _ = printWithLabels ("Operations with zero:")
18+
val _ = printWithLabels ("0 andb 0 =", 0 andb 0)
19+
val _ = printWithLabels ("0 orb 0 =", 0 orb 0)
20+
val _ = printWithLabels ("0 xorb 0 =", 0 xorb 0)
21+
val _ = printWithLabels ("0 << 10 =", 0 << 10)
22+
val _ = printWithLabels ("0 >> 10 =", 0 >> 10)
23+
24+
(* Test shift amounts *)
25+
val _ = printWithLabels ("Large shift amounts:")
26+
val _ = printWithLabels ("1 << 31 =", 1 << 31)
27+
val _ = printWithLabels ("1 << 32 =", 1 << 32)
28+
val _ = printWithLabels ("-2147483648 >> 31 =", (-2147483648) >> 31)
29+
val _ = printWithLabels ("-2147483648 ~>> 31 =", (-2147483648) ~>> 31)
30+
31+
in printWithLabels "Edge case tests completed!"
32+
end
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
2025-07-29T00:49:05.562Z [RTM] info: Skipping network creation. Observe that all external IO operations will yield a runtime error.
2+
7@{}%{}
3+
12@{}%{}
4+
5@{}%{}
5+
8@{}%{}
6+
4@{}%{}
7+
2147483647@{}%{}
8+
>>> Main thread finished with value: ()@{}%{}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
(* Simple bit operations test *)
2+
let val _ = printWithLabels (15 andb 7)
3+
val _ = printWithLabels (8 orb 4)
4+
val _ = printWithLabels (15 xorb 10)
5+
val _ = printWithLabels (1 << 3)
6+
val _ = printWithLabels (16 >> 2)
7+
val _ = printWithLabels ((-1) ~>> 1)
8+
in ()
9+
end

tests/rt/pos/core/bitops.golden

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
2025-07-29T00:49:05.562Z [RTM] info: Skipping network creation. Observe that all external IO operations will yield a runtime error.
2+
("bitAnd 15 & 7 ="@{}%{}, 7@{}%{})@{}%{}
3+
("bitAnd 255 & 128 ="@{}%{}, 128@{}%{})@{}%{}
4+
("bitAnd 0 & 65535 ="@{}%{}, 0@{}%{})@{}%{}
5+
("bitOr 8 | 4 ="@{}%{}, 12@{}%{})@{}%{}
6+
("bitOr 1 | 2 | 4 ="@{}%{}, 7@{}%{})@{}%{}
7+
("bitOr 0 | 255 ="@{}%{}, 255@{}%{})@{}%{}
8+
("bitXor 15 ^ 10 ="@{}%{}, 5@{}%{})@{}%{}
9+
("bitXor 255 ^ 255 ="@{}%{}, 0@{}%{})@{}%{}
10+
("bitXor 170 ^ 85 ="@{}%{}, 255@{}%{})@{}%{}
11+
("bitShiftLeft 1 << 3 ="@{}%{}, 8@{}%{})@{}%{}
12+
("bitShiftRight 16 >> 2 ="@{}%{}, 4@{}%{})@{}%{}
13+
("bitZeroShiftRight 4294967295 >>> 1 ="@{}%{}, 2147483647@{}%{})@{}%{}
14+
("HAMT-style index calculation: (42 >> 5) & 31 ="@{}%{}, 1@{}%{})@{}%{}
15+
"All bit operation tests completed!"@{}%{}
16+
>>> Main thread finished with value: ()@{}%{}

tests/rt/pos/core/bitops.trp

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
let
2+
val test_bitAnd =
3+
let val a = 15 andb 7 in
4+
let val b = 255 andb 128 in
5+
let val c = 0 andb 65535 in
6+
let val _ = printWithLabels ("bitAnd 15 & 7 =", a) in
7+
let val _ = printWithLabels ("bitAnd 255 & 128 =", b) in
8+
printWithLabels ("bitAnd 0 & 65535 =", c)
9+
end
10+
end
11+
end
12+
end
13+
end
14+
15+
val test_bitOr =
16+
let val a = 8 orb 4 in
17+
let val b = 1 orb 2 orb 4 in
18+
let val c = 0 orb 255 in
19+
let val _ = printWithLabels ("bitOr 8 | 4 =", a) in
20+
let val _ = printWithLabels ("bitOr 1 | 2 | 4 =", b) in
21+
printWithLabels ("bitOr 0 | 255 =", c)
22+
end
23+
end
24+
end
25+
end
26+
end
27+
28+
val test_bitXor =
29+
let val a = 15 xorb 10 in
30+
let val b = 255 xorb 255 in
31+
let val c = 170 xorb 85 in
32+
let val _ = printWithLabels ("bitXor 15 ^ 10 =", a) in
33+
let val _ = printWithLabels ("bitXor 255 ^ 255 =", b) in
34+
printWithLabels ("bitXor 170 ^ 85 =", c)
35+
end
36+
end
37+
end
38+
end
39+
end
40+
41+
val test_bitShift =
42+
let val a = 1 << 3 in
43+
let val b = 16 >> 2 in
44+
let val c = 4294967295 ~>> 1 in
45+
let val _ = printWithLabels ("bitShiftLeft 1 << 3 =", a) in
46+
let val _ = printWithLabels ("bitShiftRight 16 >> 2 =", b) in
47+
printWithLabels ("bitZeroShiftRight 4294967295 >>> 1 =", c)
48+
end
49+
end
50+
end
51+
end
52+
end
53+
54+
val test_complex =
55+
let val hash = 42 in
56+
let val shift = 5 in
57+
let val mask = 31 in
58+
let val index = (hash >> shift) andb mask in
59+
printWithLabels ("HAMT-style index calculation: (42 >> 5) & 31 =", index)
60+
end
61+
end
62+
end
63+
end
64+
65+
in
66+
let val _ = test_bitAnd in
67+
let val _ = test_bitOr in
68+
let val _ = test_bitXor in
69+
let val _ = test_bitShift in
70+
let val _ = test_complex in
71+
printWithLabels "All bit operation tests completed!"
72+
end
73+
end
74+
end
75+
end
76+
end
77+
end

0 commit comments

Comments
 (0)