This commit is contained in:
parent
99180eb3b4
commit
bf907c3872
48
Cargo.lock
generated
48
Cargo.lock
generated
|
@ -69,6 +69,18 @@ dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "arrayref"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "arrayvec"
|
||||||
|
version = "0.7.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
@ -109,6 +121,20 @@ dependencies = [
|
||||||
"wyz",
|
"wyz",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "blake3"
|
||||||
|
version = "1.5.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7"
|
||||||
|
dependencies = [
|
||||||
|
"arrayref",
|
||||||
|
"arrayvec",
|
||||||
|
"cc",
|
||||||
|
"cfg-if",
|
||||||
|
"constant_time_eq",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "block-buffer"
|
name = "block-buffer"
|
||||||
version = "0.10.4"
|
version = "0.10.4"
|
||||||
|
@ -118,6 +144,15 @@ dependencies = [
|
||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.1.28"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2e80e3b6a3ab07840e1cae9b0666a63970dc28e8ed5ffbcdacbfc760c281bfc1"
|
||||||
|
dependencies = [
|
||||||
|
"shlex",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
@ -170,6 +205,12 @@ version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
|
checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "constant_time_eq"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cpufeatures"
|
name = "cpufeatures"
|
||||||
version = "0.2.12"
|
version = "0.2.12"
|
||||||
|
@ -242,6 +283,7 @@ name = "fayalite"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitvec",
|
"bitvec",
|
||||||
|
"blake3",
|
||||||
"clap",
|
"clap",
|
||||||
"eyre",
|
"eyre",
|
||||||
"fayalite-proc-macros",
|
"fayalite-proc-macros",
|
||||||
|
@ -521,6 +563,12 @@ dependencies = [
|
||||||
"digest",
|
"digest",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "shlex"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
|
|
|
@ -19,6 +19,7 @@ fayalite-proc-macros-impl = { version = "=0.2.0", path = "crates/fayalite-proc-m
|
||||||
fayalite-visit-gen = { version = "=0.2.0", path = "crates/fayalite-visit-gen" }
|
fayalite-visit-gen = { version = "=0.2.0", path = "crates/fayalite-visit-gen" }
|
||||||
base16ct = "0.2.0"
|
base16ct = "0.2.0"
|
||||||
bitvec = { version = "1.0.1", features = ["serde"] }
|
bitvec = { version = "1.0.1", features = ["serde"] }
|
||||||
|
blake3 = { version = "1.5.4", features = ["serde"] }
|
||||||
clap = { version = "4.5.9", features = ["derive", "env", "string"] }
|
clap = { version = "4.5.9", features = ["derive", "env", "string"] }
|
||||||
eyre = "0.6.12"
|
eyre = "0.6.12"
|
||||||
hashbrown = "0.14.3"
|
hashbrown = "0.14.3"
|
||||||
|
|
|
@ -15,6 +15,7 @@ version.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bitvec.workspace = true
|
bitvec.workspace = true
|
||||||
|
blake3.workspace = true
|
||||||
clap.workspace = true
|
clap.workspace = true
|
||||||
eyre.workspace = true
|
eyre.workspace = true
|
||||||
fayalite-proc-macros.workspace = true
|
fayalite-proc-macros.workspace = true
|
||||||
|
|
|
@ -12,6 +12,7 @@ use clap::{
|
||||||
Parser, Subcommand, ValueEnum, ValueHint,
|
Parser, Subcommand, ValueEnum, ValueHint,
|
||||||
};
|
};
|
||||||
use eyre::{eyre, Report};
|
use eyre::{eyre, Report};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
error,
|
error,
|
||||||
ffi::OsString,
|
ffi::OsString,
|
||||||
|
@ -197,8 +198,9 @@ impl BaseArgs {
|
||||||
&self,
|
&self,
|
||||||
_acquired_job: &mut AcquiredJob,
|
_acquired_job: &mut AcquiredJob,
|
||||||
mut command: process::Command,
|
mut command: process::Command,
|
||||||
|
mut captured_output: Option<&mut String>,
|
||||||
) -> io::Result<process::ExitStatus> {
|
) -> io::Result<process::ExitStatus> {
|
||||||
if self.redirect_output_for_rust_test {
|
if self.redirect_output_for_rust_test || captured_output.is_some() {
|
||||||
let (reader, writer) = os_pipe::pipe()?;
|
let (reader, writer) = os_pipe::pipe()?;
|
||||||
let mut reader = io::BufReader::new(reader);
|
let mut reader = io::BufReader::new(reader);
|
||||||
command.stderr(writer.try_clone()?);
|
command.stderr(writer.try_clone()?);
|
||||||
|
@ -209,6 +211,9 @@ impl BaseArgs {
|
||||||
Ok(loop {
|
Ok(loop {
|
||||||
let status = child.try_wait()?;
|
let status = child.try_wait()?;
|
||||||
streaming_read_utf8(&mut reader, |s| {
|
streaming_read_utf8(&mut reader, |s| {
|
||||||
|
if let Some(captured_output) = captured_output.as_deref_mut() {
|
||||||
|
captured_output.push_str(s);
|
||||||
|
}
|
||||||
// use print! so output goes to Rust test output capture
|
// use print! so output goes to Rust test output capture
|
||||||
print!("{s}");
|
print!("{s}");
|
||||||
io::Result::Ok(())
|
io::Result::Ok(())
|
||||||
|
@ -369,6 +374,7 @@ pub struct VerilogArgs {
|
||||||
pub struct VerilogOutput {
|
pub struct VerilogOutput {
|
||||||
pub firrtl: FirrtlOutput,
|
pub firrtl: FirrtlOutput,
|
||||||
pub verilog_files: Vec<PathBuf>,
|
pub verilog_files: Vec<PathBuf>,
|
||||||
|
pub contents_hash: Option<blake3::Hash>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VerilogOutput {
|
impl VerilogOutput {
|
||||||
|
@ -386,6 +392,7 @@ impl VerilogArgs {
|
||||||
let file_separator_prefix = "\n// ----- 8< ----- FILE \"";
|
let file_separator_prefix = "\n// ----- 8< ----- FILE \"";
|
||||||
let file_separator_suffix = "\" ----- 8< -----\n\n";
|
let file_separator_suffix = "\" ----- 8< -----\n\n";
|
||||||
let mut input = &*input;
|
let mut input = &*input;
|
||||||
|
output.contents_hash = Some(blake3::hash(input.as_bytes()));
|
||||||
let main_verilog_file = output.main_verilog_file();
|
let main_verilog_file = output.main_verilog_file();
|
||||||
let mut file_name: Option<&Path> = Some(&main_verilog_file);
|
let mut file_name: Option<&Path> = Some(&main_verilog_file);
|
||||||
loop {
|
loop {
|
||||||
|
@ -428,6 +435,7 @@ impl VerilogArgs {
|
||||||
let output = VerilogOutput {
|
let output = VerilogOutput {
|
||||||
firrtl: firrtl_output,
|
firrtl: firrtl_output,
|
||||||
verilog_files: vec![],
|
verilog_files: vec![],
|
||||||
|
contents_hash: None,
|
||||||
};
|
};
|
||||||
let mut cmd = process::Command::new(firtool);
|
let mut cmd = process::Command::new(firtool);
|
||||||
cmd.arg(output.firrtl.firrtl_file());
|
cmd.arg(output.firrtl.firrtl_file());
|
||||||
|
@ -442,7 +450,7 @@ impl VerilogArgs {
|
||||||
}
|
}
|
||||||
cmd.args(firtool_extra_args);
|
cmd.args(firtool_extra_args);
|
||||||
cmd.current_dir(&output.firrtl.output_dir);
|
cmd.current_dir(&output.firrtl.output_dir);
|
||||||
let status = firrtl.base.run_external_command(acquired_job, cmd)?;
|
let status = firrtl.base.run_external_command(acquired_job, cmd, None)?;
|
||||||
if status.success() {
|
if status.success() {
|
||||||
self.process_unadjusted_verilog_file(output)
|
self.process_unadjusted_verilog_file(output)
|
||||||
} else {
|
} else {
|
||||||
|
@ -541,7 +549,7 @@ pub struct FormalArgs {
|
||||||
)]
|
)]
|
||||||
pub sby: PathBuf,
|
pub sby: PathBuf,
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
pub sby_extra_args: Vec<OsString>,
|
pub sby_extra_args: Vec<String>,
|
||||||
#[arg(long, default_value_t)]
|
#[arg(long, default_value_t)]
|
||||||
pub mode: FormalMode,
|
pub mode: FormalMode,
|
||||||
#[arg(long, default_value_t = Self::DEFAULT_DEPTH)]
|
#[arg(long, default_value_t = Self::DEFAULT_DEPTH)]
|
||||||
|
@ -550,6 +558,8 @@ pub struct FormalArgs {
|
||||||
pub solver: String,
|
pub solver: String,
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
pub smtbmc_extra_args: Vec<String>,
|
pub smtbmc_extra_args: Vec<String>,
|
||||||
|
#[arg(long, default_value_t = true, env = "FAYALITE_CACHE_RESULTS")]
|
||||||
|
pub cache_results: bool,
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
_formal_adjust_args: FormalAdjustArgs,
|
_formal_adjust_args: FormalAdjustArgs,
|
||||||
}
|
}
|
||||||
|
@ -564,16 +574,18 @@ impl fmt::Debug for FormalArgs {
|
||||||
depth,
|
depth,
|
||||||
solver,
|
solver,
|
||||||
smtbmc_extra_args,
|
smtbmc_extra_args,
|
||||||
|
cache_results,
|
||||||
_formal_adjust_args: _,
|
_formal_adjust_args: _,
|
||||||
} = self;
|
} = self;
|
||||||
f.debug_struct("FormalArgs")
|
f.debug_struct("FormalArgs")
|
||||||
.field("verilog", &verilog)
|
.field("verilog", verilog)
|
||||||
.field("sby", &sby)
|
.field("sby", sby)
|
||||||
.field("sby_extra_args", &sby_extra_args)
|
.field("sby_extra_args", sby_extra_args)
|
||||||
.field("mode", &mode)
|
.field("mode", mode)
|
||||||
.field("depth", &depth)
|
.field("depth", depth)
|
||||||
.field("solver", &solver)
|
.field("solver", solver)
|
||||||
.field("smtbmc_extra_args", &smtbmc_extra_args)
|
.field("smtbmc_extra_args", smtbmc_extra_args)
|
||||||
|
.field("cache_results", cache_results)
|
||||||
.finish_non_exhaustive()
|
.finish_non_exhaustive()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -592,6 +604,48 @@ impl FormalOutput {
|
||||||
pub fn sby_file(&self) -> PathBuf {
|
pub fn sby_file(&self) -> PathBuf {
|
||||||
self.verilog.firrtl.file_with_ext("sby")
|
self.verilog.firrtl.file_with_ext("sby")
|
||||||
}
|
}
|
||||||
|
pub fn cache_file(&self) -> PathBuf {
|
||||||
|
self.verilog.firrtl.file_with_ext("cache.json")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub struct FormalCacheOutput {}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum FormalCacheVersion {
|
||||||
|
V1,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FormalCacheVersion {
|
||||||
|
pub const CURRENT: Self = Self::V1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub struct FormalCache {
|
||||||
|
pub version: FormalCacheVersion,
|
||||||
|
pub contents_hash: blake3::Hash,
|
||||||
|
pub stdout_stderr: String,
|
||||||
|
pub result: Result<FormalCacheOutput, String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FormalCache {
|
||||||
|
pub fn new(
|
||||||
|
version: FormalCacheVersion,
|
||||||
|
contents_hash: blake3::Hash,
|
||||||
|
stdout_stderr: String,
|
||||||
|
result: Result<FormalCacheOutput, String>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
version,
|
||||||
|
contents_hash,
|
||||||
|
stdout_stderr,
|
||||||
|
result,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FormalArgs {
|
impl FormalArgs {
|
||||||
|
@ -604,6 +658,7 @@ impl FormalArgs {
|
||||||
depth,
|
depth,
|
||||||
smtbmc_extra_args,
|
smtbmc_extra_args,
|
||||||
solver,
|
solver,
|
||||||
|
cache_results: _,
|
||||||
_formal_adjust_args: _,
|
_formal_adjust_args: _,
|
||||||
} = self;
|
} = self;
|
||||||
let smtbmc_options = smtbmc_extra_args.join(" ");
|
let smtbmc_options = smtbmc_extra_args.join(" ");
|
||||||
|
@ -644,7 +699,19 @@ impl FormalArgs {
|
||||||
verilog: verilog_output,
|
verilog: verilog_output,
|
||||||
};
|
};
|
||||||
let sby_file = output.sby_file();
|
let sby_file = output.sby_file();
|
||||||
std::fs::write(&sby_file, self.sby_contents(&output)?)?;
|
let sby_contents = self.sby_contents(&output)?;
|
||||||
|
let contents_hash = output.verilog.contents_hash.map(|verilog_hash| {
|
||||||
|
let mut hasher = blake3::Hasher::new();
|
||||||
|
hasher.update(verilog_hash.as_bytes());
|
||||||
|
hasher.update(sby_contents.as_bytes());
|
||||||
|
hasher.update(&(self.sby_extra_args.len() as u64).to_le_bytes());
|
||||||
|
for sby_extra_arg in self.sby_extra_args.iter() {
|
||||||
|
hasher.update(&(sby_extra_arg.len() as u64).to_le_bytes());
|
||||||
|
hasher.update(sby_extra_arg.as_bytes());
|
||||||
|
}
|
||||||
|
hasher.finalize()
|
||||||
|
});
|
||||||
|
std::fs::write(&sby_file, sby_contents)?;
|
||||||
let mut cmd = process::Command::new(&self.sby);
|
let mut cmd = process::Command::new(&self.sby);
|
||||||
cmd.arg("-f");
|
cmd.arg("-f");
|
||||||
cmd.arg(sby_file.file_name().unwrap());
|
cmd.arg(sby_file.file_name().unwrap());
|
||||||
|
@ -656,20 +723,62 @@ impl FormalArgs {
|
||||||
NonZeroUsize::new(1).unwrap()
|
NonZeroUsize::new(1).unwrap()
|
||||||
};
|
};
|
||||||
let new_minimum_count = AcquiredJob::max_available_job_count().min(new_minimum_count);
|
let new_minimum_count = AcquiredJob::max_available_job_count().min(new_minimum_count);
|
||||||
|
let mut captured_output = String::new();
|
||||||
|
let cache_file = output.cache_file();
|
||||||
|
let do_cache = if let Some(contents_hash) = contents_hash.filter(|_| self.cache_results) {
|
||||||
|
if let Some(FormalCache {
|
||||||
|
version: FormalCacheVersion::CURRENT,
|
||||||
|
contents_hash: cache_contents_hash,
|
||||||
|
stdout_stderr,
|
||||||
|
result,
|
||||||
|
}) = fs::read(&cache_file)
|
||||||
|
.ok()
|
||||||
|
.and_then(|v| serde_json::from_slice(&v).ok())
|
||||||
|
{
|
||||||
|
if cache_contents_hash == contents_hash {
|
||||||
|
println!("Using cached formal result:\n{stdout_stderr}");
|
||||||
|
return match result {
|
||||||
|
Ok(FormalCacheOutput {}) => Ok(output),
|
||||||
|
Err(error) => Err(CliError(eyre::Report::msg(error))),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
let _ = fs::remove_file(&cache_file);
|
||||||
let status = acquired_job.increase_job_count(new_minimum_count, |acquired_job| {
|
let status = acquired_job.increase_job_count(new_minimum_count, |acquired_job| {
|
||||||
self.verilog
|
self.verilog.firrtl.base.run_external_command(
|
||||||
.firrtl
|
acquired_job,
|
||||||
.base
|
cmd,
|
||||||
.run_external_command(acquired_job, cmd)
|
do_cache.then_some(&mut captured_output),
|
||||||
|
)
|
||||||
})?;
|
})?;
|
||||||
if status.success() {
|
let result = if status.success() {
|
||||||
Ok(output)
|
Ok(output)
|
||||||
} else {
|
} else {
|
||||||
Err(CliError(eyre!(
|
Err(CliError(eyre!(
|
||||||
"running {} failed: {status}",
|
"running {} failed: {status}",
|
||||||
self.sby.display()
|
self.sby.display()
|
||||||
)))
|
)))
|
||||||
|
};
|
||||||
|
if do_cache {
|
||||||
|
fs::write(
|
||||||
|
cache_file,
|
||||||
|
serde_json::to_string_pretty(&FormalCache {
|
||||||
|
version: FormalCacheVersion::CURRENT,
|
||||||
|
contents_hash: contents_hash.unwrap(),
|
||||||
|
stdout_stderr: captured_output,
|
||||||
|
result: match &result {
|
||||||
|
Ok(FormalOutput { verilog: _ }) => Ok(FormalCacheOutput {}),
|
||||||
|
Err(error) => Err(error.to_string()),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.expect("serialization shouldn't ever fail"),
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue