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

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