lib/std/lang/gen/bitset.rad 5.0 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 = wordsFor(bs.len);
96
    for i in 0..numWords {
97
        total += popCount(bs.bits[i]);
98
    }
99
    return total;
100
}
101
102
/// Population count for a 32-bit word.
103
fn popCount(x: u32) -> u32 {
104
    let mut n = x;
105
    n -= ((n >> 1) & 0x55555555);
106
    n = (n & 0x33333333) + ((n >> 2) & 0x33333333);
107
    n = (n + (n >> 4)) & 0x0F0F0F0F;
108
    n += (n >> 8);
109
    n += (n >> 16);
110
111
    return n & 0x3F;
112
}
113
114
/// Union: `dst = dst | src`.
115
pub fn union_(dst: *mut Bitset, src: *Bitset) {
116
    let numWords = wordsFor(dst.len);
117
    let srcWords = wordsFor(src.len);
118
    let minWords = min(numWords, srcWords);
119
    for i in 0..minWords {
120
        dst.bits[i] |= src.bits[i];
121
    }
122
}
123
124
/// Subtract: `dst = dst - src`.
125
pub fn subtract(dst: *mut Bitset, src: *Bitset) {
126
    let numWords = wordsFor(dst.len);
127
    let srcWords = wordsFor(src.len);
128
    let minWords = min(numWords, srcWords);
129
    for i in 0..minWords {
130
        dst.bits[i] &= ~src.bits[i];
131
    }
132
}
133
134
/// Check if two bitsets are equal.
135
pub fn eq(a: *Bitset, b: *Bitset) -> bool {
136
    let numWordsA = wordsFor(a.len);
137
    let numWordsB = wordsFor(b.len);
138
    let maxWords = max(numWordsA, numWordsB);
139
140
    for i in 0..maxWords {
141
        let wordA = a.bits[i] if i < numWordsA else 0;
142
        let wordB = b.bits[i] if i < numWordsB else 0;
143
        if wordA != wordB {
144
            return false;
145
        }
146
    }
147
    return true;
148
}
149
150
/// Copy bits from source to destination.
151
pub fn copy(dst: *mut Bitset, src: *Bitset) {
152
    let numWords = wordsFor(dst.len);
153
    let srcWords = wordsFor(src.len);
154
    let minWords = min(numWords, srcWords);
155
156
    for i in 0..minWords {
157
        dst.bits[i] = src.bits[i];
158
    }
159
    // Clear remaining words if destination is larger.
160
    for i in minWords..numWords {
161
        dst.bits[i] = 0;
162
    }
163
}
164
165
/// Clear all bits.
166
pub fn clearAll(bs: *mut Bitset) {
167
    let numWords = wordsFor(bs.len);
168
    for i in 0..numWords {
169
        bs.bits[i] = 0;
170
    }
171
}
172
173
/// Iterator state for iterating set bits.
174
pub record BitIter {
175
    bs: *Bitset,
176
    wordIdx: u32,
177
    bitIdx: u32,
178
}
179
180
/// Create an iterator over set bits.
181
pub fn iter(bs: *Bitset) -> BitIter {
182
    return BitIter { bs, wordIdx: 0, bitIdx: 0 };
183
}
184
185
/// Get the next set bit, or nil if none remain.
186
pub fn iterNext(it: *mut BitIter) -> ?u32 {
187
    let numWords = wordsFor(it.bs.len);
188
    while it.wordIdx < numWords {
189
        let word = it.bs.bits[it.wordIdx];
190
        // Skip empty words entirely.
191
        if word == 0 and it.bitIdx == 0 {
192
            it.wordIdx += 1;
193
        } else {
194
            while it.bitIdx < 32 {
195
                let n = it.wordIdx * 32 + it.bitIdx;
196
                if n >= it.bs.len {
197
                    return nil;
198
                }
199
                it.bitIdx += 1;
200
                if (word & (1 << (it.bitIdx - 1))) != 0 {
201
                    return n;
202
                }
203
            }
204
            it.wordIdx += 1;
205
            it.bitIdx = 0;
206
        }
207
    }
208
    return nil;
209
}