| 228 | |
| 229 | #[inline(always)] |
| 230 | fn classify_counts(counts: &mut [u64], strategy: BucketStrategy) { |
| 231 | let lut = match strategy { |
| 232 | BucketStrategy::Any => &ANY_BIT, |
| 233 | BucketStrategy::Afl => &AFL_COUNT_LOOKUP_16, |
| 234 | BucketStrategy::AflFirst => &AFL_FIRST_COUNT_LOOKUP_16, |
| 235 | BucketStrategy::SmallCounts => &SMALL_COUNT_LOOKUP_16, |
| 236 | }; |
| 237 | |
| 238 | // Manually unrolling the loop to operate in chunks of 4 results in minor (but measurable) speed |
| 239 | // improvements |
| 240 | for entry in counts.chunks_exact_mut(4) { |
| 241 | // The `counts` array is generally sparse, so most entries will be zero and we can exit |
| 242 | // early if this condition is true |
| 243 | if *entry == [0; 4] { |
| 244 | continue; |
| 245 | } |
| 246 | |
| 247 | for word in bytemuck::cast_slice_mut(entry) { |
| 248 | *word = lut[*word as usize]; |
| 249 | } |
| 250 | } |
| 251 | } |
| 252 | |
| 253 | /// Buckets inputs into either hit or not hit. |
| 254 | #[rustfmt::skip] |