Skip to content

Commit

Permalink
Implement manual SIMD parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
alion02 committed Dec 2, 2024
1 parent 85fba08 commit fc6d810
Showing 1 changed file with 73 additions and 22 deletions.
95 changes: 73 additions & 22 deletions src/day1.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
#![allow(
unsafe_op_in_unsafe_fn,
clippy::missing_safety_doc,
clippy::identity_op
clippy::identity_op,
clippy::zero_prefixed_literal
)]

use std::{fmt::Display, simd::prelude::*};
use std::{
arch::x86_64::{__m256i, _mm256_madd_epi16, _mm256_maddubs_epi16},
fmt::Display,
simd::prelude::*,
};

#[repr(align(32))]
#[derive(Clone, Copy)]
Expand All @@ -26,31 +31,55 @@ macro_rules! get_arr {
}

#[inline(never)]
#[target_feature(enable = "avx2,bmi1,bmi2,cmpxchg16b,lzcnt,movbe,popcnt")]
unsafe fn preprocess(s: &str, left: &mut [u8; 90032], right: &mut [u8; 90032]) {
let s = s.as_bytes();

let mut i = 0;

while i < 14000 {
let a = *s.get_unchecked(i + 0) as u32 * 10000
+ *s.get_unchecked(i + 1) as u32 * 1000
+ *s.get_unchecked(i + 2) as u32 * 100
+ *s.get_unchecked(i + 3) as u32 * 10
+ *s.get_unchecked(i + 4) as u32 * 1
- 543328;

*left.get_unchecked_mut(a as usize) += 1;

let b = *s.get_unchecked(i + 8) as u32 * 10000
+ *s.get_unchecked(i + 9) as u32 * 1000
+ *s.get_unchecked(i + 10) as u32 * 100
+ *s.get_unchecked(i + 11) as u32 * 10
+ *s.get_unchecked(i + 12) as u32 * 1
- 543328;

*right.get_unchecked_mut(b as usize) += 1;

i += 14;
while i < s.len() {
let chunk =
(s.get_unchecked(i) as *const _ as *const u8x32).read_unaligned() - Simd::splat(b'0');
let shuffled_chunk = simd_swizzle!(chunk, [
00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 13, 13, //
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 27, 27, //
]);

let s1 = _mm256_maddubs_epi16(
shuffled_chunk.into(),
u8x32::from_array([
10, 1, 10, 1, 1, 0, 0, 0, 10, 1, 10, 1, 1, 0, 0, 0, //
10, 1, 10, 1, 1, 0, 0, 0, 10, 1, 10, 1, 1, 0, 0, 0, //
])
.into(),
);

let s2: u16x16 = _mm256_madd_epi16(
s1,
u16x16::from_array([100, 1, 1, 0, 100, 1, 1, 0, 100, 1, 1, 0, 100, 1, 1, 0]).into(),
)
.into();

let s3: __m256i =
simd_swizzle!(s2, [0, 2, 4, 6, 0, 2, 4, 6, 8, 10, 12, 14, 8, 10, 12, 14]).into();

let s4: u32x8 = _mm256_madd_epi16(
s3,
u16x16::from_array([10, 1, 10, 1, 0, 0, 0, 0, 10, 1, 10, 1, 0, 0, 0, 0]).into(),
)
.into();

let a1 = s4[0];
let b1 = s4[1];
let a2 = s4[4];
let b2 = s4[5];

*left.get_unchecked_mut(a1 as usize - 10000) += 1;
*left.get_unchecked_mut(a2 as usize - 10000) += 1;
*right.get_unchecked_mut(b1 as usize - 10000) += 1;
*right.get_unchecked_mut(b2 as usize - 10000) += 1;

i += 28;
}
}

Expand Down Expand Up @@ -139,3 +168,25 @@ pub fn part1(s: &str) -> impl Display {
pub fn part2(s: &str) -> impl Display {
unsafe { inner2(s) }
}

#[cfg(test)]
mod tests {
use std::fs::read_to_string;

use super::*;

#[test]
fn test() {
let s = read_to_string("./inputs/1.txt").unwrap();
let s = s.as_str();

assert_eq!(
part1(s).to_string(),
read_to_string("./outputs/1p1.txt").unwrap(),
);
assert_eq!(
part2(s).to_string(),
read_to_string("./outputs/1p2.txt").unwrap(),
);
}
}

0 comments on commit fc6d810

Please sign in to comment.