diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3ea589f..d1159bc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,8 @@ jobs: needs: - test - simd - - msrv + - msrv_x64 + - msrv_aarch64 - miri steps: - run: exit 0 @@ -109,8 +110,8 @@ jobs: RUSTFLAGS: -C target_feature=${{ matrix.target_feature }} CARGO_CFG_HTTPARSE_DISABLE_SIMD_COMPILETIME: ${{ matrix.disable_compiletime }} - msrv: - name: msrv + msrv_x64: + name: msrv (x64) runs-on: ubuntu-latest steps: - name: Checkout @@ -123,12 +124,40 @@ jobs: toolchain: 1.36.0 override: true - # Only build, dev-dependencies don't compile on 1.10 + # Only build, dev-dependencies don't compile on 1.36.0 - name: Build uses: actions-rs/cargo@v1 with: command: build + # This tests that aarch64 gracefully fallbacks to SWAR if neon_intrinsics aren't available (<1.59) + msrv_aarch64: + name: msrv (aarch64) + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v1 + + - name: Install cross-compiling dependencies + run: | + sudo apt-get update + sudo apt-get install -y gcc-aarch64-linux-gnu + + - name: Setup Rust + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: 1.36.0 + override: true + target: aarch64-unknown-linux-gnu + + # Only build, dev-dependencies don't compile on 1.36.0 + - name: Build + uses: actions-rs/cargo@v1 + with: + command: build + args: --target aarch64-unknown-linux-gnu + miri: name: Test with Miri runs-on: ubuntu-latest diff --git a/build.rs b/build.rs index 3831590..624be6e 100644 --- a/build.rs +++ b/build.rs @@ -1,11 +1,10 @@ use std::env; -//use std::ffi::OsString; -//use std::process::Command; +use std::ffi::OsString; +use std::process::Command; fn main() { - // We don't currently need to check the Version anymore... - // But leaving this in place in case we need to in the future. - /* + // We check rustc version to enable features beyond MSRV, such as: + // - 1.59 => neon_intrinsics let rustc = env::var_os("RUSTC").unwrap_or(OsString::from("rustc")); let output = Command::new(&rustc) .arg("--version") @@ -13,28 +12,25 @@ fn main() { .expect("failed to check 'rustc --version'") .stdout; - let version = String::from_utf8(output) + let raw_version = String::from_utf8(output) .expect("rustc version output should be utf-8"); - */ - - enable_new_features(/*&version*/); -} - -fn enable_new_features(/*raw_version: &str*/) { - /* - let version = match Version::parse(raw_version) { + + let version = match Version::parse(&raw_version) { Ok(version) => version, Err(err) => { println!("cargo:warning=failed to parse `rustc --version`: {}", err); return; } }; - */ - enable_simd(/*version*/); + enable_new_features(version); } -fn enable_simd(/*version: Version*/) { +fn enable_new_features(version: Version) { + enable_simd(version); +} + +fn enable_simd(version: Version) { if env::var_os("CARGO_FEATURE_STD").is_none() { println!("cargo:warning=building for no_std disables httparse SIMD"); return; @@ -50,6 +46,11 @@ fn enable_simd(/*version: Version*/) { return; } + // 1.59.0 is the first version to support neon_intrinsics + if version >= Version(1, 59, 0) { + println!("cargo:rustc-cfg=httparse_simd_neon_intrinsics"); + } + println!("cargo:rustc-cfg=httparse_simd"); // cfg(target_feature) isn't stable yet, but CARGO_CFG_TARGET_FEATURE has @@ -83,79 +84,46 @@ fn enable_simd(/*version: Version*/) { return }, }; - - let mut saw_sse42 = false; - let mut saw_avx2 = false; - - for feature in feature_list.split(',') { - let feature = feature.trim(); - if !saw_sse42 && feature == "sse4.2" { - saw_sse42 = true; - println!("cargo:rustc-cfg=httparse_simd_target_feature_sse42"); - } - - if !saw_avx2 && feature == "avx2" { - saw_avx2 = true; - println!("cargo:rustc-cfg=httparse_simd_target_feature_avx2"); - } + + let features = feature_list.split(',').map(|s| s.trim()); + if features.clone().any(|f| f == "sse4.2") { + println!("cargo:rustc-cfg=httparse_simd_target_feature_sse42"); + } + if features.clone().any(|f| f == "avx2") { + println!("cargo:rustc-cfg=httparse_simd_target_feature_avx2"); } } -/* #[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] -struct Version { - major: u32, - minor: u32, - patch: u32, -} +struct Version (u32, u32, u32); impl Version { - fn parse(mut s: &str) -> Result { + fn parse(s: &str) -> Result { if !s.starts_with("rustc ") { return Err(format!("unrecognized version string: {}", s)); } - s = &s["rustc ".len()..]; - - let parts: Vec<&str> = s.split(".").collect(); - if parts.len() < 3 { - return Err(format!("not enough version parts: {:?}", parts)); - } - - let mut num = String::new(); - for c in parts[0].chars() { - if !c.is_digit(10) { - break; - } - num.push(c); - } - let major = num.parse::().map_err(|e| e.to_string())?; - - num.clear(); - for c in parts[1].chars() { - if !c.is_digit(10) { - break; - } - num.push(c); - } - let minor = num.parse::().map_err(|e| e.to_string())?; - - num.clear(); - for c in parts[2].chars() { - if !c.is_digit(10) { - break; - } - num.push(c); + let s = s.trim_start_matches("rustc "); + + let mut iter = s + .split(".") + .take(3) + .map(|s| match s.find(|c: char| !c.is_ascii_digit()) { + Some(end) => &s[..end], + None => s, + }) + .map(|s| s.parse::().map_err(|e| e.to_string())); + + if iter.clone().count() != 3 { + return Err(format!("not enough version parts: {:?}", s)); } - let patch = num.parse::().map_err(|e| e.to_string())?; + + let major = iter.next().unwrap()?; + let minor = iter.next().unwrap()?; + let patch = iter.next().unwrap()?; - Ok(Version { - major: major, - minor: minor, - patch: patch, - }) + Ok(Version(major, minor, patch)) } } -*/ fn var_is(key: &str, val: &str) -> bool { match env::var(key) { diff --git a/src/simd/mod.rs b/src/simd/mod.rs index 81bdd87..63464b4 100644 --- a/src/simd/mod.rs +++ b/src/simd/mod.rs @@ -5,7 +5,10 @@ mod swar; any( target_arch = "x86", target_arch = "x86_64", - target_arch = "aarch64", + all( + target_arch = "aarch64", + httparse_simd_neon_intrinsics, + ) ), )))] pub use self::swar::*; @@ -137,11 +140,13 @@ pub use self::avx2_compile_time::*; #[cfg(all( httparse_simd, target_arch = "aarch64", + httparse_simd_neon_intrinsics, ))] mod neon; #[cfg(all( httparse_simd, target_arch = "aarch64", + httparse_simd_neon_intrinsics, ))] pub use self::neon::*;