lib/std/lang/gen/bitset.rad 5.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
/// Return the maximum of two 32-bit values.
18
fn max(a: u32, b: u32) -> u32 {
19
    if a > b {
20
        return a;
21
    }
22
    return b;
23
}
24
25
/// Calculate the number of 32-bit words needed to store `n` bits.
26
pub fn wordsFor(n: u32) -> u32 {
27
    return (n + 31) / 32;
28
}
29
30
/// A fixed-size bitset backed by an array of 32-bit words.
31
pub record Bitset {
32
    /// Backing storage for bits, organized as 32-bit words.
33
    bits: *mut [u32],
34
    /// Number of bits this bitset can hold.
35
    len: u32,
36
}
37
38
/// Create a new bitset backed by the given zero-initialized storage.
39
pub fn new(bits: *mut [u32]) -> Bitset {
40
    return Bitset { bits, len: bits.len * 32 };
41
}
42
43
/// Create a new bitset backed by the given storage, zeroing it first.
44
pub fn init(bits: *mut [u32]) -> Bitset {
45
    for i in 0..bits.len {
46
        bits[i] = 0;
47
    }
48
    return new(bits);
49
}
50
51
/// Create a bitset from arena allocation.
52
pub fn allocate(arena: *mut alloc::Arena, len: u32) -> Bitset throws (alloc::AllocError) {
53
    let numWords = wordsFor(len);
54
    let bits = try alloc::allocSlice(arena, @sizeOf(u32), @alignOf(u32), numWords) as *mut [u32];
55
56
    return init(bits);
57
}
58
59
/// Set bit `n` in the bitset.
60
pub fn set(bs: *mut Bitset, n: u32) {
61
    if n >= bs.len {
62
        return;
63
    }
64
    let word = n / 32;
65
    let b = n % 32;
66
67
    bs.bits[word] |= (1 << b);
68
}
69
70
/// Clear bit `n` in the bitset.
71
pub fn clear(bs: *mut Bitset, n: u32) {
72
    if n >= bs.len {
73
        return;
74
    }
75
    let word = n / 32;
76
    let b = n % 32;
77
78
    bs.bits[word] &= ~(1 << b);
79
}
80
81
/// Check if bit `n` is set.
82
pub fn contains(bs: *Bitset, n: u32) -> bool {
83
    if n >= bs.len {
84
        return false;
85
    }
86
    let word = n / 32;
87
    let b = n % 32;
88
89
    return (bs.bits[word] & (1 << b)) != 0;
90
}
91
92
/// Count the number of set bits.
93
pub fn count(bs: *Bitset) -> u32 {
94
    let mut total: u32 = 0;
95
    let numWords = bs.bits.len;
96
    for i in 0..numWords {
97
        let word = bs.bits[i];
98
        if word != 0 {
99
            total += popCount(word);
100
        }
101
    }
102
    return total;
103
}
104
105
/// Population count for a 32-bit word.
106
fn popCount(x: u32) -> u32 {
107
    let mut n = x;
108
    n -= ((n >> 1) & 0x55555555);
109
    n = (n & 0x33333333) + ((n >> 2) & 0x33333333);
110
    n = (n + (n >> 4)) & 0x0F0F0F0F;
111
    n += (n >> 8);
112
    n += (n >> 16);
113
114
    return n & 0x3F;
115
}
116
117
/// Union: `dst = dst | src`.
118
pub fn union_(dst: *mut Bitset, src: *Bitset) {
119
    let numWords = dst.bits.len;
120
    let srcWords = src.bits.len;
121
    let minWords = min(numWords, srcWords);
122
    for i in 0..minWords {
123
        dst.bits[i] |= src.bits[i];
124
    }
125
}
126
127
/// Subtract: `dst = dst - src`.
128
pub fn subtract(dst: *mut Bitset, src: *Bitset) {
129
    let numWords = dst.bits.len;
130
    let srcWords = src.bits.len;
131
    let minWords = min(numWords, srcWords);
132
    for i in 0..minWords {
133
        dst.bits[i] &= ~src.bits[i];
134
    }
135
}
136
137
/// Check if two bitsets are equal.
138
pub fn eq(a: *Bitset, b: *Bitset) -> bool {
139
    let numWordsA = a.bits.len;
140
    let numWordsB = b.bits.len;
141
    let maxWords = max(numWordsA, numWordsB);
142
143
    for i in 0..maxWords {
144
        let wordA = a.bits[i] if i < numWordsA else 0;
145
        let wordB = b.bits[i] if i < numWordsB else 0;
146
        if wordA != wordB {
147
            return false;
148
        }
149
    }
150
    return true;
151
}
152
153
/// Copy bits from source to destination.
154
pub 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
        dst.bits[i] = src.bits[i];
161
    }
162
    // Clear remaining words if destination is larger.
163
    for i in minWords..numWords {
164
        dst.bits[i] = 0;
165
    }
166
}
167
168
/// Clear all bits.
169
pub fn clearAll(bs: *mut Bitset) {
170
    let numWords = bs.bits.len;
171
    for i in 0..numWords {
172
        bs.bits[i] = 0;
173
    }
174
}
175
176
/// Iterator state for iterating set bits.
177
pub record BitIter {
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
pub 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
pub 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
        it.wordIdx += 1;
198
        if it.wordIdx >= numWords {
199
            return nil;
200
        }
201
        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
    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
    const DEBRUIJN: u32 = 0x077CB531;
221
    const 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
}