Skip to content

Commit 850f348

Browse files
committed
feat: Write mutation conflicts as raw bit matrix words during codegen
This representation is much more compact than writing out the conflict pairs, and improves compile times significantly. In the case of bevy_math with 5109 mutations and 559157 mutation conflicts, this change reduces compile times from 32.7 seconds down to just 18.3 seconds.
1 parent c722370 commit 850f348

3 files changed

Lines changed: 32 additions & 10 deletions

File tree

mutest-emit/src/codegen/harness.rs

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -294,15 +294,33 @@ fn mk_active_mutant_handle_static(sp: Span) -> Box<ast::Item> {
294294
}
295295

296296
pub fn bake_mutation_conflicts(sp: Span, mutation_conflict_graph: &MutationConflictGraph) -> Box<ast::Expr> {
297-
let pair_exprs = mutation_conflict_graph.iter_conflicts_excluding_unsafe()
298-
.map(|(a, b)| {
299-
let a_expr = ast::mk::expr_u32(sp, a.index());
300-
let b_expr = ast::mk::expr_u32(sp, b.index());
301-
ast::mk::expr_tuple(sp, thin_vec![a_expr, b_expr])
302-
})
303-
.collect::<ThinVec<_>>();
304-
let pairs_expr = ast::mk::expr_slice(sp, pair_exprs);
305-
ast::mk::expr_call_path(sp, ast::mk::path_local(path::static_bit_matrix_from_symmetric_pairs(sp)), thin_vec![pairs_expr])
297+
let n = mutation_conflict_graph.total_mutations_count() + 1;
298+
const WORD_BYTES: usize = size_of::<u64>();
299+
const WORD_BITS: usize = WORD_BYTES * 8;
300+
let words_per_row = n.div_ceil(WORD_BITS);
301+
302+
let mut words = vec![0_u64; n * words_per_row];
303+
for (a, b) in mutation_conflict_graph.iter_conflicts_excluding_unsafe() {
304+
let a = a.index() as usize;
305+
let b = b.index() as usize;
306+
307+
let mut set_bit_in_words = |row: usize, column: usize| {
308+
let row_first_word_idx = row * words_per_row;
309+
let word_idx_offset = column / WORD_BITS;
310+
let word_mask = 1 << (column % WORD_BITS);
311+
let word = &mut words[row_first_word_idx + word_idx_offset];
312+
*word |= word_mask;
313+
};
314+
315+
set_bit_in_words(a, b);
316+
set_bit_in_words(b, a);
317+
}
318+
319+
let word_exprs = words.into_iter().map(|word| ast::mk::expr_lit(sp, ast::token::LitKind::Integer, Symbol::intern(&word.to_string()), None)).collect::<ThinVec<_>>();
320+
let words_expr = ast::mk::expr_slice(sp, word_exprs);
321+
322+
// StaticBitMatrix::from_raw_words(&[ ... ])
323+
ast::mk::expr_call_path(sp, ast::mk::path_local(path::static_bit_matrix_from_raw_words(sp)), thin_vec![words_expr])
306324
}
307325

308326
fn mk_mutation_conflict_matrix_const<'trg, 'm>(sp: Span, mutation_conflict_graph: &MutationConflictGraph) -> Box<ast::Item> {

mutest-emit/src/codegen/symbols.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ pub mod path {
161161
mutest_main_static (::mutest_runtime::mutest_main_static),
162162
StandaloneMutantMeta (::mutest_runtime::StandaloneMutantMeta),
163163
StaticBitMatrix (::mutest_runtime::StaticBitMatrix),
164-
static_bit_matrix_from_symmetric_pairs (::mutest_runtime::StaticBitMatrix::from_symmetric_pairs),
164+
static_bit_matrix_from_raw_words (::mutest_runtime::StaticBitMatrix::from_raw_words),
165165
static_map (::mutest_runtime::static_map),
166166
SubstMap (crate::mutest_generated::SubstMap),
167167
SubstMapTrait (::mutest_runtime::SubstMap),

mutest-runtime/src/data_structures/static_bit_matrix.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ where
4343
matrix
4444
}
4545

46+
pub const fn from_raw_words(words: &[Word]) -> Self {
47+
Self { words: *words.as_array().unwrap() }
48+
}
49+
4650
pub const fn set(&mut self, row: u32, column: u32) {
4751
assert!(row < N && column < N);
4852
let row = row as usize;

0 commit comments

Comments
 (0)