lib/std/lang/gen/bitset.rad 5.7 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 + 31) / 32;
20
}
21
22
/// A fixed-size bitset backed by an array of 32-bit words.
23
export record Bitset: Copy {
24
    /// Backing storage for bits, organized as 32-bit words.
25
    bits: *mut [u32],
26
    /// Number of bits this bitset can hold.
27
    len: u32,
28
}
29
30
/// Create a new bitset backed by the given zero-initialized storage.
31
export fn new(bits: *mut [u32]) -> Bitset {
32
    return Bitset { bits, len: bits.len * 32 };
33
}
34
35
/// Create a new bitset backed by the given storage, zeroing it first.
36
export fn init(bits: *mut [u32]) -> Bitset {
37
    for i in 0..bits.len {
38
        set bits[i] = 0;
39
    }
40
    return new(bits);
41
}
42
43
/// Create a bitset from arena allocation.
44
export fn allocate(arena: *mut alloc::Arena, len: u32) -> Bitset throws (alloc::AllocError) {
45
    let numWords = wordsFor(len);
46
    let bits = try alloc::allocSlice(arena, @sizeOf(u32), @alignOf(u32), numWords) as *mut [u32];
47
48
    return init(bits);
49
}
50
51
/// Set bit `n` in the bitset.
52
export fn put(bs: *mut Bitset, n: u32) {
53
    if n >= bs.len {
54
        return;
55
    }
56
    let word = n / 32;
57
    let b = n % 32;
58
59
    set bs.bits[word] |= (1 << b);
60
}
61
62
/// Clear bit `n` in the bitset.
63
export fn clear(bs: *mut Bitset, n: u32) {
64
    if n >= bs.len {
65
        return;
66
    }
67
    let word = n / 32;
68
    let b = n % 32;
69
70
    set bs.bits[word] &= ~(1 << b);
71
}
72
73
/// Check if bit `n` is set.
74
export fn contains(bs: *Bitset, n: u32) -> bool {
75
    if n >= bs.len {
76
        return false;
77
    }
78
    let word = n / 32;
79
    let b = n % 32;
80
81
    return (bs.bits[word] & (1 << b)) <> 0;
82
}
83
84
/// Count the number of set bits.
85
export fn count(bs: *Bitset) -> u32 {
86
    let mut total: u32 = 0;
87
    let numWords = bs.bits.len;
88
    for i in 0..numWords {
89
        let word = bs.bits[i];
90
        if word <> 0 {
91
            set total += popCount(word);
92
        }
93
    }
94
    return total;
95
}
96
97
/// Population count for a 32-bit word.
98
fn popCount(x: u32) -> u32 {
99
    let mut n = x;
100
    set n -= ((n >> 1) & 0x55555555);
101
    set n = (n & 0x33333333) + ((n >> 2) & 0x33333333);
102
    set n = (n + (n >> 4)) & 0x0F0F0F0F;
103
    set n += (n >> 8);
104
    set n += (n >> 16);
105
106
    return n & 0x3F;
107
}
108
109
/// Union: `dst = dst | src`.
110
export fn union_(dst: *mut Bitset, src: *Bitset) {
111
    let numWords = dst.bits.len;
112
    let srcWords = src.bits.len;
113
    let minWords = min(numWords, srcWords);
114
    for i in 0..minWords {
115
        set dst.bits[i] |= src.bits[i];
116
    }
117
}
118
119
/// Subtract: `dst = dst - src`.
120
export fn subtract(dst: *mut Bitset, src: *Bitset) {
121
    let numWords = dst.bits.len;
122
    let srcWords = src.bits.len;
123
    let minWords = min(numWords, srcWords);
124
    for i in 0..minWords {
125
        set dst.bits[i] &= ~src.bits[i];
126
    }
127
}
128
129
/// Check if two bitsets are equal.
130
export fn eq(a: *Bitset, b: *Bitset) -> bool {
131
    let numWordsA = a.bits.len;
132
    let numWordsB = b.bits.len;
133
    let minWords = min(numWordsA, numWordsB);
134
135
    for i in 0..minWords {
136
        if a.bits[i] <> b.bits[i] {
137
            return false;
138
        }
139
    }
140
    for i in minWords..numWordsA {
141
        if a.bits[i] <> 0 {
142
            return false;
143
        }
144
    }
145
    for i in minWords..numWordsB {
146
        if b.bits[i] <> 0 {
147
            return false;
148
        }
149
    }
150
    return true;
151
}
152
153
/// Copy bits from source to destination.
154
export fn copy(dst: *mut Bitset, src: *Bitset) {
155
    let numWords = dst.bits.len;
156
    let srcWords = src.bits.len;
157
    let minWords = min(numWords, srcWords);
158
159
    for i in 0..minWords {
160
        set dst.bits[i] = src.bits[i];
161
    }
162
    // Clear remaining words if destination is larger.
163
    for i in minWords..numWords {
164
        set dst.bits[i] = 0;
165
    }
166
}
167
168
/// Clear all bits.
169
export fn clearAll(bs: *mut Bitset) {
170
    let numWords = bs.bits.len;
171
    for i in 0..numWords {
172
        set bs.bits[i] = 0;
173
    }
174
}
175
176
/// Iterator state for iterating set bits.
177
export record BitIter: Copy {
178
    /// Bitset being iterated.
179
    bs: *Bitset,
180
    /// Current word index.
181
    wordIdx: u32,
182
    /// Remaining bits in the current word (visited bits cleared).
183
    remaining: u32,
184
}
185
186
/// Create an iterator over set bits.
187
export fn iter(bs: *Bitset) -> BitIter {
188
    let remaining = bs.bits[0] if bs.len > 0 else 0;
189
    return BitIter { bs, wordIdx: 0, remaining };
190
}
191
192
/// Get the next set bit, or nil if none remain.
193
export fn iterNext(it: *mut BitIter) -> ?u32 {
194
    let numWords = it.bs.bits.len;
195
    // Skip to next non-zero word.
196
    while it.remaining == 0 {
197
        set it.wordIdx += 1;
198
        if it.wordIdx >= numWords {
199
            return nil;
200
        }
201
        set it.remaining = it.bs.bits[it.wordIdx];
202
    }
203
    // Find lowest set bit position using de Bruijn sequence.
204
    let b = ctz(it.remaining);
205
    let n = it.wordIdx * 32 + b;
206
    if n >= it.bs.len {
207
        return nil;
208
    }
209
    // Clear the lowest set bit.
210
    set it.remaining &= it.remaining - 1;
211
212
    return n;
213
}
214
215
/// Count trailing zeros in a 32-bit value.
216
/// Returns the bit position of the lowest set bit (0-31).
217
/// Behavior is undefined if `x` is 0.
218
fn ctz(x: u32) -> u32 {
219
    // De Bruijn sequence for 32-bit CTZ.
220
    constant DEBRUIJN: u32 = 0x077CB531;
221
    constant TABLE: [u8; 32] = [
222
         0,  1, 28,  2, 29, 14, 24,  3, 30, 22, 20, 15, 25, 17,  4,  8,
223
        31, 27, 13, 23, 21, 19, 16,  7, 26, 12, 18,  6, 11,  5, 10,  9,
224
    ];
225
    // Isolate lowest set bit, multiply by de Bruijn constant, look up.
226
    let isolated = x & (~x + 1);
227
228
    return TABLE[(isolated * DEBRUIJN) >> 27] as u32;
229
}