diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index f94a057..0d06a13 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -25,6 +25,7 @@ jobs: cargo test --release - name: Test LLVM Intrinsics run: | + sudo apt update && sudo apt install clang-16 cargo clippy --features llvm-intrinsics --all-targets -- -D warnings cargo test --features llvm-intrinsics cargo test --features llvm-intrinsics --release diff --git a/README.md b/README.md index 053decb..c008111 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,24 @@ in order to actually take advantage of the the optimized assembly: RUSTFLAGS="-Clinker-plugin-lto -Clinker=clang -Clink-arg=-fuse-ld=lld" cargo build ``` +Note that **the `clang` version must match the `rustc` LLVM version**. If not, +it is possible to encounter errors when running the `ethnum-intrinsics` build +script. You can verify the LLVM version used by `rustc` with: + +```sh +rustc --version --verbose | grep LLVM +``` + +In particular, this affects macOS which ships its own `clang` binary. The +`ethnum-intrinsics` build script accepts a `CLANG` environment variable to +specity a specific `clang` executable path to use. Using the major LLVM +version from the command above: + +``` +brew install llvm@${LLVM_VERSION} +CLANG=/opt/homebrew/opt/llvm@${LLVM_VERSION}/bin/clang cargo build +``` + ### API Stability The instinsics are exported under `ethnum::intrinsics`. That being said, be diff --git a/intrinsics/build/main.rs b/intrinsics/build/main.rs index 43032f2..bb063cf 100644 --- a/intrinsics/build/main.rs +++ b/intrinsics/build/main.rs @@ -15,6 +15,11 @@ use cc::Build; use std::{env, error::Error, fs, path::PathBuf, process::Command}; fn main() -> Result<(), Box> { + println!("cargo:rerun-if-env-changed=CLANG"); + let clang = env::var("CLANG") + .map(PathBuf::from) + .unwrap_or_else(|_| "clang".into()); + let out_dir = PathBuf::from(env::var("OUT_DIR")?); let template = { @@ -35,24 +40,15 @@ fn main() -> Result<(), Box> { let source = template .replace("i128", "i256") .replace(" 127", " 255") - .replace("dereferenceable(16)", "dereferenceable(32)") - // TODO(nlordell): Figure out why Clang doesn't like these - .replace("mustprogress ", "") - .replace("noundef ", "") - .replace("memory(argmem: readwrite) ", "") - .replace("memory(argmem: read) ", "") - .replace("memory(none) ", "") - .replace(", !!1", ""); + .replace("dereferenceable(16)", "dereferenceable(32)"); + let path = out_dir.join("intrinsics.ll"); fs::write(&path, source)?; path }; let mut build = Build::new(); - build - .compiler("clang") - .file(intrinsics_ir_path) - .opt_level(3); + build.compiler(&clang).file(intrinsics_ir_path).opt_level(3); let linker_plugin_lto = matches!(env::var("RUSTFLAGS"), Ok(flags) if flags.contains("-Clinker-plugin-lto"));