From ae95ad873328b6143c7fac6ab5831b542f6c517f Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Mon, 29 Jun 2020 15:58:08 -0700 Subject: [PATCH] cranelift: Don't build `peepmatic`-based optimizations in `build.rs` Instead, when the `rebuild-peephole-optimizers` feature is enabled, rebuild them the first time they are used. This allows peepmatic to run when Cranelift's `Opcode` is defined and available, which paves the way forward for: * merging `peepmatic_runtime::operator::Operator` and Cranelift's `Opcode` (we are wasting a bunch of cycles converting between the two of them), and * supporting vcode optimizations in `peepmatic`. --- .github/workflows/main.yml | 11 ++----- cranelift/codegen/Cargo.toml | 2 +- cranelift/codegen/build.rs | 23 +++++--------- cranelift/codegen/src/peepmatic.rs | 50 ++++++++++++++++++++++++++++-- 4 files changed, 59 insertions(+), 27 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ed195c3d2d..074cd2531c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -162,16 +162,11 @@ jobs: --package peepmatic-macro \ --package peepmatic-runtime \ --package peepmatic-test - - name: Rebuild Cranelift's peepmatic-based peephole optimizers - run: | - cd cranelift/ - cargo build --features 'enable-peepmatic cranelift-codegen/rebuild-peephole-optimizers' + - name: Rebuild Peepmatic-based peephole optimizers and test them + run: cargo test --features 'enable-peepmatic cranelift-codegen/rebuild-peephole-optimizers' + working-directory: ./cranelift - name: Check that peephole optimizers are up to date run: git diff --exit-code - - name: Test `cranelift-codegen` with `peepmatic` enabled - run: | - cd cranelift/ - cargo test --features 'enable-peepmatic' # Perform all tests (debug mode) for `wasmtime`. This runs stable/beta/nightly # channels of Rust as well as macOS/Linux/Windows. diff --git a/cranelift/codegen/Cargo.toml b/cranelift/codegen/Cargo.toml index d5bd49d0d5..be40645534 100644 --- a/cranelift/codegen/Cargo.toml +++ b/cranelift/codegen/Cargo.toml @@ -25,6 +25,7 @@ gimli = { version = "0.21.0", default-features = false, features = ["write"], op smallvec = { version = "1.0.0" } thiserror = "1.0.4" byteorder = { version = "1.3.2", default-features = false } +peepmatic = { path = "../peepmatic", optional = true, version = "0.66.0" } peepmatic-runtime = { path = "../peepmatic/crates/runtime", optional = true, version = "0.2.0" } regalloc = { version = "0.0.28" } # It is a goal of the cranelift-codegen crate to have minimal external dependencies. @@ -34,7 +35,6 @@ regalloc = { version = "0.0.28" } [build-dependencies] cranelift-codegen-meta = { path = "meta", version = "0.66.0" } -peepmatic = { path = "../peepmatic", optional = true, version = "0.66.0" } [features] default = ["std", "unwind"] diff --git a/cranelift/codegen/build.rs b/cranelift/codegen/build.rs index 2caf32609d..c456908845 100644 --- a/cranelift/codegen/build.rs +++ b/cranelift/codegen/build.rs @@ -90,20 +90,11 @@ fn main() { } #[cfg(feature = "rebuild-peephole-optimizers")] - rebuild_peephole_optimizers(); -} - -#[cfg(feature = "rebuild-peephole-optimizers")] -fn rebuild_peephole_optimizers() { - use std::path::Path; - - let source_path = Path::new("src").join("preopt.peepmatic"); - println!("cargo:rerun-if-changed={}", source_path.display()); - - let preopt = - peepmatic::compile_file(&source_path).expect("failed to compile `src/preopt.peepmatic`"); - - preopt - .serialize_to_file(&Path::new("src").join("preopt.serialized")) - .expect("failed to serialize peephole optimizer to `src/preopt.serialized`"); + { + std::fs::write( + std::path::Path::new(&out_dir).join("CRANELIFT_CODEGEN_PATH"), + cur_dir.to_str().unwrap(), + ) + .unwrap() + } } diff --git a/cranelift/codegen/src/peepmatic.rs b/cranelift/codegen/src/peepmatic.rs index 2c6c2d1e01..8c098e6bcf 100644 --- a/cranelift/codegen/src/peepmatic.rs +++ b/cranelift/codegen/src/peepmatic.rs @@ -19,6 +19,7 @@ use peepmatic_runtime::{ r#type::{BitWidth, Kind, Type}, PeepholeOptimizations, PeepholeOptimizer, }; +use std::borrow::Cow; use std::boxed::Box; use std::convert::{TryFrom, TryInto}; use std::ptr; @@ -28,7 +29,34 @@ use std::sync::atomic::{AtomicPtr, Ordering}; pub(crate) fn preopt<'a, 'b>( isa: &'b dyn TargetIsa, ) -> PeepholeOptimizer<'static, 'a, &'b dyn TargetIsa> { - static SERIALIZED: &[u8] = include_bytes!("preopt.serialized"); + #[cfg(feature = "rebuild-peephole-optimizers")] + fn get_serialized() -> Cow<'static, [u8]> { + use std::fs; + use std::path::Path; + + let codegen_path = Path::new(include_str!(concat!( + env!("OUT_DIR"), + "/CRANELIFT_CODEGEN_PATH" + ))); + let source_path = codegen_path.join("src").join("preopt.peepmatic"); + println!("cargo:rerun-if-changed={}", source_path.display()); + + let preopt = peepmatic::compile_file(&source_path) + .expect("failed to compile `src/preopt.peepmatic`"); + + let serialized_path = codegen_path.join("src").join("preopt.serialized"); + preopt + .serialize_to_file(&serialized_path) + .expect("failed to serialize peephole optimizer to `src/preopt.serialized`"); + fs::read(&serialized_path) + .expect("failed to read `src/preopt.serialized`") + .into() + } + + #[cfg(not(feature = "rebuild-peephole-optimizers"))] + fn get_serialized() -> Cow<'static, [u8]> { + static SERIALIZED: &[u8] = include_bytes!("preopt.serialized"); + } // Once initialized, this must never be re-assigned. The initialized value // is semantically "static data" and is intentionally leaked for the whole @@ -46,7 +74,7 @@ pub(crate) fn preopt<'a, 'b>( // another thread could be doing the same thing concurrently, so there is a // race to see who initializes `DESERIALIZED` first, and we need to be // prepared to both win or lose that race. - let peep_opts = PeepholeOptimizations::deserialize(SERIALIZED) + let peep_opts = PeepholeOptimizations::deserialize(&get_serialized()) .expect("should always be able to deserialize `preopt.serialized`"); let peep_opts = Box::into_raw(Box::new(peep_opts)); @@ -891,3 +919,21 @@ unsafe impl<'a, 'b> InstructionSet<'b> for &'a dyn TargetIsa { self.pointer_bits() } } + +#[cfg(test)] +#[cfg(feature = "x86")] +mod tests { + use super::*; + use crate::isa::lookup; + use crate::settings::{builder, Flags}; + use std::str::FromStr; + use target_lexicon::triple; + + #[test] + fn get_peepmatic_preopt() { + let isa = lookup(triple!("x86_64")) + .expect("expect x86 ISA") + .finish(Flags::new(builder())); + let _ = preopt(&*isa); + } +}