lib/std/lang/gen/bitset.rad 4.6 KiB raw
1
//! Bitset utilities for register tracking.
2
//!
3
//! Provides efficient bit-level set operations for tracking live registers
4
//! during liveness analysis and register allocation.
5
@test mod tests;
6
7
use std::lang::alloc;
8
9
/// Return the minimum of two 32-bit values.
10
fn min(a: u32, b: u32) -> u32 {
11
    if a < b {
12
        return a;
13
    }
14
    return b;
15
}
16
17
/// Calculate the number of 32-bit words needed to store `n` bits.
18
export fn wordsFor(n: u32) -> u32 {
19
    return n / 32 + (1 if n % 32 > 0 else 0);
20
}
21
22
/// Allocate zeroed words for at least `len` bits in a session.
23
export fn allocate 'bits (storage: &Session 'bits, len: u32) -> &'bits mut [u32] throws (alloc::AllocError) {
24
    return try storage.fill(0 as u32, wordsFor(len));
25
}
26
27
/// Set bit `n` in the bitset.
28
export fn put(bs: &mut [u32], n: u32) {
29
    let word = n / 32;
30
    if word >= bs.len {
31
        return;
32
    }
33
    let b = n % 32;
34
35
    set bs[word] |= (1 << b);
36
}
37
38
/// Clear bit `n` in the bitset.
39
export fn clear(bs: &mut [u32], n: u32) {
40
    let word = n / 32;
41
    if word >= bs.len {
42
        return;
43
    }
44
    let b = n % 32;
45
46
    set bs[word] &= ~(1 << b);
47
}
48
49
/// Check if bit `n` is set.
50
export fn contains(bs: &[u32], n: u32) -> bool {
51
    let word = n / 32;
52
    if word >= bs.len {
53
        return false;
54
    }
55
    let b = n % 32;
56
57
    return (bs[word] & (1 << b)) <> 0;
58
}
59
60
/// Count the number of set bits.
61
export fn count(bs: &[u32]) -> u32 {
62
    let mut total: u32 = 0;
63
    for word in bs {
64
        if word <> 0 {
65
            set total += popCount(word);
66
        }
67
    }
68
    return total;
69
}
70
71
/// Population count for a 32-bit word.
72
fn popCount(x: u32) -> u32 {
73
    let mut n = x;
74
    set n -= ((n >> 1) & 0x55555555);
75
    set n = (n & 0x33333333) + ((n >> 2) & 0x33333333);
76
    set n = (n + (n >> 4)) & 0x0F0F0F0F;
77
    set n += (n >> 8);
78
    set n += (n >> 16);
79
80
    return n & 0x3F;
81
}
82
83
/// Union: `dst = dst | src`.
84
export fn union_(dst: &mut [u32], src: &[u32]) {
85
    for i in 0..min(dst.len, src.len) {
86
        set dst[i] |= src[i];
87
    }
88
}
89
90
/// Subtract: `dst = dst - src`.
91
export fn subtract(dst: &mut [u32], src: &[u32]) {
92
    for i in 0..min(dst.len, src.len) {
93
        set dst[i] &= ~src[i];
94
    }
95
}
96
97
/// Check if two bitsets are equal.
98
export fn eq(a: &[u32], b: &[u32]) -> bool {
99
    let minWords = min(a.len, b.len);
100
101
    for i in 0..minWords {
102
        if a[i] <> b[i] {
103
            return false;
104
        }
105
    }
106
    for i in minWords..a.len {
107
        if a[i] <> 0 {
108
            return false;
109
        }
110
    }
111
    for i in minWords..b.len {
112
        if b[i] <> 0 {
113
            return false;
114
        }
115
    }
116
    return true;
117
}
118
119
/// Copy bits from source to destination.
120
export fn copy(dst: &mut [u32], src: &[u32]) {
121
    let minWords = min(dst.len, src.len);
122
123
    for i in 0..minWords {
124
        set dst[i] = src[i];
125
    }
126
    // Clear remaining words if destination is larger.
127
    for i in minWords..dst.len {
128
        set dst[i] = 0;
129
    }
130
}
131
132
/// Clear all bits.
133
export fn clearAll(bs: &mut [u32]) {
134
    for i in 0..bs.len {
135
        set bs[i] = 0;
136
    }
137
}
138
139
/// Iterator state for iterating set bits.
140
export record BitIter: Copy {
141
    /// Current word index.
142
    wordIdx: u32,
143
    /// Remaining bits in the current word (visited bits cleared).
144
    remaining: u32,
145
}
146
147
/// Create an iterator over set bits.
148
/// The cursor retains the first word mask and its position.
149
export fn iter(bs: &[u32]) -> BitIter {
150
    let remaining = bs[0] if bs.len > 0 else 0;
151
    return BitIter { wordIdx: 0, remaining };
152
}
153
154
/// Get the next set bit from the supplied bitset, or nil if none remain.
155
/// The current word mask is a value snapshot; later words are read on demand.
156
export fn iterNext(it: &mut BitIter, bs: &[u32]) -> ?u32 {
157
    // Skip to next non-zero word.
158
    while it.remaining == 0 {
159
        set it.wordIdx += 1;
160
        if it.wordIdx >= bs.len {
161
            return nil;
162
        }
163
        set it.remaining = bs[it.wordIdx];
164
    }
165
    // Find lowest set bit position using de Bruijn sequence.
166
    let b = ctz(it.remaining);
167
    let n = it.wordIdx * 32 + b;
168
    // Clear the lowest set bit.
169
    set it.remaining &= it.remaining - 1;
170
171
    return n;
172
}
173
174
/// Count trailing zeros in a 32-bit value.
175
/// Returns the bit position of the lowest set bit (0-31).
176
/// Behavior is undefined if `x` is 0.
177
fn ctz(x: u32) -> u32 {
178
    // De Bruijn sequence for 32-bit CTZ.
179
    constant DEBRUIJN: u32 = 0x077CB531;
180
    constant TABLE: [u8; 32] = [
181
         0,  1, 28,  2, 29, 14, 24,  3, 30, 22, 20, 15, 25, 17,  4,  8,
182
        31, 27, 13, 23, 21, 19, 16,  7, 26, 12, 18,  6, 11,  5, 10,  9,
183
    ];
184
    // Isolate lowest set bit, multiply by de Bruijn constant, look up.
185
    let isolated = x & (~x + 1);
186
187
    return TABLE[(isolated * DEBRUIJN) >> 27] as u32;
188
}