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`.
This commit is contained in:
Nick Fitzgerald
2020-06-29 15:58:08 -07:00
parent 978070c020
commit ae95ad8733
4 changed files with 59 additions and 27 deletions

View File

@@ -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.

View File

@@ -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"]

View File

@@ -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()
}
}

View File

@@ -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);
}
}