From 5190aaece63ce83bbe4b8907b4c67501b95ddd0e Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Wed, 29 Nov 2023 21:02:37 -0500 Subject: [PATCH 01/73] skeleton isla tool --- Cargo.lock | 2 + cranelift/isle/veri/veri_engine/Cargo.toml | 9 +++ cranelift/isle/veri/veri_engine/src/isla.rs | 71 +++++++++++++++++++++ 3 files changed, 82 insertions(+) create mode 100644 cranelift/isle/veri/veri_engine/src/isla.rs diff --git a/Cargo.lock b/Cargo.lock index 26a44dbe1a7f..3043a5b1af68 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3033,10 +3033,12 @@ dependencies = [ name = "veri_engine" version = "0.1.0" dependencies = [ + "anyhow", "clap 3.2.25", "cranelift-codegen", "cranelift-codegen-meta", "cranelift-isle", + "cranelift-reader", "easy-smt", "env_logger 0.10.0", "itertools", diff --git a/cranelift/isle/veri/veri_engine/Cargo.toml b/cranelift/isle/veri/veri_engine/Cargo.toml index 6894eab445a5..fba2b62b7765 100644 --- a/cranelift/isle/veri/veri_engine/Cargo.toml +++ b/cranelift/isle/veri/veri_engine/Cargo.toml @@ -13,10 +13,16 @@ path = "src/lib.rs" name = "veri_engine_bin" path = "src/main.rs" +[[bin]] +name = "isla" +path = "src/isla.rs" + [dependencies] cranelift-isle = { path = "../../isle" } cranelift-codegen = { path = "../../../codegen" } +cranelift-reader = { path = "../../../reader" } cranelift-codegen-meta = { path = "../../../codegen/meta" } +anyhow = { workspace = true } veri_ir = { path = "../veri_ir" } easy-smt = { git = "https://github.com/elliottt/easy-smt.git" } clap = { version = "3.0.0", features = ["derive"] } @@ -28,3 +34,6 @@ retry = "2.0.0" [dev-dependencies] strum = "0.24.0" strum_macros = "0.24.0" + +[features] +default = ["cranelift-codegen/all-arch", "cranelift-codegen/trace-log"] diff --git a/cranelift/isle/veri/veri_engine/src/isla.rs b/cranelift/isle/veri/veri_engine/src/isla.rs new file mode 100644 index 000000000000..6ca3f474a47d --- /dev/null +++ b/cranelift/isle/veri/veri_engine/src/isla.rs @@ -0,0 +1,71 @@ +use anyhow::Context as _; +use clap::Parser; +use cranelift_codegen::print_errors::pretty_error; +use cranelift_codegen::Context; +use cranelift_reader::{parse_sets_and_triple, parse_test, ParseOptions}; +use std::fs::File; +use std::io::{self, Read}; +use std::path::{Path, PathBuf}; + +#[derive(Parser)] +struct Options { + /// Configure Cranelift settings. + #[clap(long = "set")] + settings: Vec, + + /// Specify the Cranelift target. + #[clap(long = "target")] + target: String, + + /// Specify an input file to be used. Use '-' for stdin. + file: PathBuf, +} + +fn main() -> anyhow::Result<()> { + let options = Options::parse(); + + // Parse input CLIF test file. + let buffer = read_to_string(&options.file)?; + let test_file = parse_test(&buffer, ParseOptions::default()) + .with_context(|| format!("failed to parse {}", options.file.to_string_lossy()))?; + + // Determine ISA settings. + let parsed = parse_sets_and_triple(&options.settings, &options.target)?; + let fisa = parsed.as_fisa(); + let isa = fisa.isa.or(test_file.isa_spec.unique_isa()); + + let isa = match isa { + None => anyhow::bail!("compilation requires a target isa"), + Some(isa) => isa, + }; + + // Compile functions. + for (func, _) in test_file.functions { + let mut context = Context::for_function(func); + let mut mem = vec![]; + let _compiled_code = context + .compile_and_emit(isa, &mut mem, &mut Default::default()) + .map_err(|err| anyhow::anyhow!("{}", pretty_error(&err.func, err.inner)))?; + println!("bytes: {:?}", mem); + } + + Ok(()) +} + +/// Read an entire file into a string. +fn read_to_string>(path: P) -> anyhow::Result { + let mut buffer = String::new(); + let path = path.as_ref(); + if path == Path::new("-") { + let stdin = io::stdin(); + let mut stdin = stdin.lock(); + stdin + .read_to_string(&mut buffer) + .context("failed to read stdin to string")?; + } else { + let mut file = File::open(path)?; + file.read_to_string(&mut buffer) + .with_context(|| format!("failed to read {} to string", path.display()))?; + } + Ok(buffer) +} From 1c8692a234f33ca8b52e4e98076fd4ff9f8b43c7 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Thu, 30 Nov 2023 00:12:29 -0500 Subject: [PATCH 02/73] integrate isla --- Cargo.lock | 385 +++++++++++++++++++- cranelift/isle/veri/veri_engine/Cargo.toml | 1 + cranelift/isle/veri/veri_engine/src/isla.rs | 77 +++- 3 files changed, 454 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3043a5b1af68..324bf0607196 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,17 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "ahash" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + [[package]] name = "ahash" version = "0.8.3" @@ -112,6 +123,15 @@ dependencies = [ "derive_arbitrary", ] +[[package]] +name = "ascii-canvas" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" +dependencies = [ + "term", +] + [[package]] name = "async-trait" version = "0.1.73" @@ -197,13 +217,34 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +dependencies = [ + "block-padding", + "byte-tools", + "byteorder", + "generic-array 0.12.4", +] + [[package]] name = "block-buffer" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array", + "generic-array 0.14.7", +] + +[[package]] +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +dependencies = [ + "byte-tools", ] [[package]] @@ -227,6 +268,12 @@ checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" name = "byte-array-literals" version = "14.0.0" +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" + [[package]] name = "byteorder" version = "1.4.3" @@ -636,7 +683,7 @@ dependencies = [ "regalloc2", "serde", "serde_derive", - "sha2", + "sha2 0.10.8", "similar", "smallvec", "souper-ir", @@ -924,6 +971,30 @@ dependencies = [ "itertools", ] +[[package]] +name = "crossbeam" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2801af0d36612ae591caa9568261fddce32ce6e08a7275ea334a06a4ad021a2c" +dependencies = [ + "cfg-if", + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + [[package]] name = "crossbeam-deque" version = "0.8.3" @@ -948,6 +1019,16 @@ dependencies = [ "scopeguard", ] +[[package]] +name = "crossbeam-queue" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.16" @@ -957,13 +1038,19 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "crypto-common" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array", + "generic-array 0.14.7", "typenum", ] @@ -993,13 +1080,28 @@ dependencies = [ "syn 2.0.37", ] +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +dependencies = [ + "generic-array 0.12.4", +] + [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", + "block-buffer 0.10.4", "crypto-common", ] @@ -1022,6 +1124,16 @@ dependencies = [ "dirs-sys", ] +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + [[package]] name = "dirs-sys" version = "0.3.7" @@ -1079,6 +1191,15 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +[[package]] +name = "ena" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" +dependencies = [ + "log", +] + [[package]] name = "encode_unicode" version = "0.3.6" @@ -1159,6 +1280,12 @@ version = "0.0.0" name = "example-wasi-wasm" version = "0.0.0" +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" + [[package]] name = "fallible-iterator" version = "0.3.0" @@ -1214,6 +1341,18 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "fixedbitset" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + [[package]] name = "flagset" version = "0.4.4" @@ -1339,6 +1478,15 @@ dependencies = [ "serde_json", ] +[[package]] +name = "generic-array" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" +dependencies = [ + "typenum", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -1414,7 +1562,7 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ - "ahash", + "ahash 0.8.3", ] [[package]] @@ -1423,7 +1571,7 @@ version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" dependencies = [ - "ahash", + "ahash 0.8.3", ] [[package]] @@ -1639,6 +1787,28 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "isla-lib" +version = "0.2.0" +source = "git+https://github.com/rems-project/isla.git#b8e614bda4a20e42c37d8b216853653133d04322" +dependencies = [ + "ahash 0.7.7", + "bincode", + "crossbeam", + "lalrpop", + "lalrpop-util", + "lazy_static", + "lexgen", + "lexgen_util", + "libc", + "petgraph 0.5.1", + "regex", + "serde", + "sha2 0.8.2", + "toml", + "z3-sys", +] + [[package]] name = "isle-fuzz" version = "0.0.0" @@ -1711,6 +1881,37 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "lalrpop" +version = "0.19.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a1cbf952127589f2851ab2046af368fd20645491bb4b376f04b7f94d7a9837b" +dependencies = [ + "ascii-canvas", + "bit-set", + "diff", + "ena", + "is-terminal", + "itertools", + "lalrpop-util", + "petgraph 0.6.4", + "regex", + "regex-syntax 0.6.29", + "string_cache", + "term", + "tiny-keccak", + "unicode-xid", +] + +[[package]] +name = "lalrpop-util" +version = "0.19.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3c48237b9604c5a4702de6b824e02006c3214327564636aef27c1028a8fa0ed" +dependencies = [ + "regex", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -1723,6 +1924,27 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" +[[package]] +name = "lexgen" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05c12789f263e189cfcffff7adaee754498e359c5fefe337f716a8122c5c55a4" +dependencies = [ + "fxhash", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "lexgen_util" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e726a67f1b0f16040843b1f12868e2e1ee6c3086a18b7502cb5046fb18da8f0" +dependencies = [ + "unicode-width", +] + [[package]] name = "libc" version = "0.2.148" @@ -1773,6 +1995,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "log" version = "0.4.20" @@ -1856,6 +2088,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "new_debug_unreachable" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" + [[package]] name = "num-traits" version = "0.2.16" @@ -1935,6 +2173,12 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" + [[package]] name = "openvino" version = "0.5.0" @@ -1974,6 +2218,29 @@ version = "6.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac" +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.4.1", + "smallvec", + "windows-targets 0.48.5", +] + [[package]] name = "paste" version = "1.0.14" @@ -1986,6 +2253,35 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +[[package]] +name = "petgraph" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7" +dependencies = [ + "fixedbitset 0.2.0", + "indexmap 1.9.3", +] + +[[package]] +name = "petgraph" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +dependencies = [ + "fixedbitset 0.4.2", + "indexmap 2.0.2", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + [[package]] name = "pin-project-lite" version = "0.2.13" @@ -2038,6 +2334,12 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + [[package]] name = "pretty_env_logger" version = "0.4.0" @@ -2230,6 +2532,15 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_users" version = "0.4.3" @@ -2473,6 +2784,18 @@ dependencies = [ "serde", ] +[[package]] +name = "sha2" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" +dependencies = [ + "block-buffer 0.7.3", + "digest 0.8.1", + "fake-simd", + "opaque-debug", +] + [[package]] name = "sha2" version = "0.10.8" @@ -2481,7 +2804,7 @@ checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", - "digest", + "digest 0.10.7", ] [[package]] @@ -2529,6 +2852,12 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "420acb44afdae038210c99e69aae24109f32f15500aa708e81d46c9f29d55fcf" +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + [[package]] name = "slab" version = "0.4.9" @@ -2611,6 +2940,19 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "string_cache" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" +dependencies = [ + "new_debug_unreachable", + "once_cell", + "parking_lot", + "phf_shared", + "precomputed-hash", +] + [[package]] name = "strsim" version = "0.10.0" @@ -2699,6 +3041,17 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + [[package]] name = "termcolor" version = "1.3.0" @@ -2784,6 +3137,15 @@ dependencies = [ "once_cell", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinytemplate" version = "1.2.1" @@ -3041,6 +3403,7 @@ dependencies = [ "cranelift-reader", "easy-smt", "env_logger 0.10.0", + "isla-lib", "itertools", "log", "retry", @@ -3481,7 +3844,7 @@ dependencies = [ "rustix", "serde", "serde_derive", - "sha2", + "sha2 0.10.8", "tempfile", "toml", "windows-sys 0.48.0", @@ -4412,6 +4775,12 @@ dependencies = [ "wast 35.0.2", ] +[[package]] +name = "z3-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae57b4c31eabc2620fbf2ea3e4deac2cd8a12522ccc0ebcc29e60dff8137de31" + [[package]] name = "zstd" version = "0.11.2+zstd.1.5.2" diff --git a/cranelift/isle/veri/veri_engine/Cargo.toml b/cranelift/isle/veri/veri_engine/Cargo.toml index fba2b62b7765..e4225e2c6834 100644 --- a/cranelift/isle/veri/veri_engine/Cargo.toml +++ b/cranelift/isle/veri/veri_engine/Cargo.toml @@ -22,6 +22,7 @@ cranelift-isle = { path = "../../isle" } cranelift-codegen = { path = "../../../codegen" } cranelift-reader = { path = "../../../reader" } cranelift-codegen-meta = { path = "../../../codegen/meta" } +isla-lib = { git = "https://github.com/rems-project/isla.git" } anyhow = { workspace = true } veri_ir = { path = "../veri_ir" } easy-smt = { git = "https://github.com/elliottt/easy-smt.git" } diff --git a/cranelift/isle/veri/veri_engine/src/isla.rs b/cranelift/isle/veri/veri_engine/src/isla.rs index 6ca3f474a47d..e77bbf204719 100644 --- a/cranelift/isle/veri/veri_engine/src/isla.rs +++ b/cranelift/isle/veri/veri_engine/src/isla.rs @@ -3,10 +3,19 @@ use clap::Parser; use cranelift_codegen::print_errors::pretty_error; use cranelift_codegen::Context; use cranelift_reader::{parse_sets_and_triple, parse_test, ParseOptions}; +use isla_lib::config::ISAConfig; use std::fs::File; use std::io::{self, Read}; use std::path::{Path, PathBuf}; +// use isla_lib::executor; +// use isla_lib::executor::{LocalFrame, StopAction, StopConditions, TaskState}; +use isla_lib::bitvector::b64::B64; +use isla_lib::bitvector::BV; +use isla_lib::ir::{Def, IRTypeInfo, Name, Symtab}; +use isla_lib::ir_lexer::new_ir_lexer; +use isla_lib::ir_parser; + #[derive(Parser)] struct Options { /// Configure Cranelift settings. @@ -17,6 +26,10 @@ struct Options { #[clap(long = "target")] target: String, + /// Architecture definition. + #[clap(long)] + arch: PathBuf, + /// Specify an input file to be used. Use '-' for stdin. file: PathBuf, } @@ -39,6 +52,11 @@ fn main() -> anyhow::Result<()> { Some(isa) => isa, }; + // Parse ISLA Architecture. + let contents = read_to_string(&options.arch)?; + let mut symtab = Symtab::new(); + let arch = parse_ir::(&contents, &mut symtab)?; + // Compile functions. for (func, _) in test_file.functions { let mut context = Context::for_function(func); @@ -46,12 +64,69 @@ fn main() -> anyhow::Result<()> { let _compiled_code = context .compile_and_emit(isa, &mut mem, &mut Default::default()) .map_err(|err| anyhow::anyhow!("{}", pretty_error(&err.func, err.inner)))?; - println!("bytes: {:?}", mem); + trace_function(&mem, &arch); } Ok(()) } +fn trace_function(mc: &[u8], arch: &Vec>) { + // &mut arch, + // symtab, + + // type_info, + let _type_info = IRTypeInfo::new(&arch); + + // TODO: &isa_config, + // TODO: assertion_mode, + // TODO: use_model_reg_init, + + //let iarch = initialize_architecture( + // &mut arch, + // symtab, + // type_info, + // &isa_config, + // assertion_mode, + // use_model_reg_init, + //); + + // let function_id = shared_state.symtab.lookup(&footprint_function); + // let (args, ret_ty, instrs) = shared_state.functions.get(&function_id).unwrap(); + // let task_state = TaskState::new().with_reset_registers(reset_registers); + // let mut task = LocalFrame::new( + // function_id, + // args, + // ret_ty, + // Some(&[opcode_val.clone()]), + // instrs, + // ) + // .add_lets(lets) + // .add_regs(regs) + // .set_memory(memory) + // .task_with_checkpoint(0, &task_state, initial_checkpoint); + // task.set_stop_conditions(&stop_conditions); + + // let num_threads = 1; + // executor::start_multi( + // num_threads, + // None, + // vec![task], + // shared_state, + // queue.clone(), + // &executor::trace_collector, + // ); +} + +fn parse_ir<'a, 'input, B: BV>( + contents: &'input str, + symtab: &'a mut Symtab<'input>, +) -> anyhow::Result>> { + match ir_parser::IrParser::new().parse(symtab, new_ir_lexer(&contents)) { + Ok(ir) => Ok(ir), + Err(_) => Err(anyhow::Error::msg("bad")), + } +} + /// Read an entire file into a string. fn read_to_string>(path: P) -> anyhow::Result { let mut buffer = String::new(); From f4af43245d190efe9b64aa354453fc535669d571 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Thu, 30 Nov 2023 11:12:20 -0500 Subject: [PATCH 03/73] it builds --- Cargo.lock | 2 + cranelift/isle/veri/veri_engine/Cargo.toml | 2 + cranelift/isle/veri/veri_engine/src/isla.rs | 123 ++++++++++++-------- 3 files changed, 79 insertions(+), 48 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 324bf0607196..06b415cb282a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3401,12 +3401,14 @@ dependencies = [ "cranelift-codegen-meta", "cranelift-isle", "cranelift-reader", + "crossbeam", "easy-smt", "env_logger 0.10.0", "isla-lib", "itertools", "log", "retry", + "sha2 0.8.2", "strum", "strum_macros", "veri_ir", diff --git a/cranelift/isle/veri/veri_engine/Cargo.toml b/cranelift/isle/veri/veri_engine/Cargo.toml index e4225e2c6834..5023ef266ee6 100644 --- a/cranelift/isle/veri/veri_engine/Cargo.toml +++ b/cranelift/isle/veri/veri_engine/Cargo.toml @@ -31,6 +31,8 @@ itertools = "0.10.3" log = "0.4.17" env_logger = "0.10.0" retry = "2.0.0" +sha2 = "0.8.1" +crossbeam = "0.8.1" [dev-dependencies] strum = "0.24.0" diff --git a/cranelift/isle/veri/veri_engine/src/isla.rs b/cranelift/isle/veri/veri_engine/src/isla.rs index e77bbf204719..47adef3c051a 100644 --- a/cranelift/isle/veri/veri_engine/src/isla.rs +++ b/cranelift/isle/veri/veri_engine/src/isla.rs @@ -4,17 +4,22 @@ use cranelift_codegen::print_errors::pretty_error; use cranelift_codegen::Context; use cranelift_reader::{parse_sets_and_triple, parse_test, ParseOptions}; use isla_lib::config::ISAConfig; +use isla_lib::smt::Checkpoint; +use sha2::{Digest, Sha256}; use std::fs::File; use std::io::{self, Read}; use std::path::{Path, PathBuf}; -// use isla_lib::executor; -// use isla_lib::executor::{LocalFrame, StopAction, StopConditions, TaskState}; +use crossbeam::queue::SegQueue; use isla_lib::bitvector::b64::B64; use isla_lib::bitvector::BV; -use isla_lib::ir::{Def, IRTypeInfo, Name, Symtab}; +use isla_lib::executor::{self, LocalFrame, TaskState}; +use isla_lib::init::initialize_architecture; +use isla_lib::ir::{AssertionMode, Def, IRTypeInfo, Name, Symtab, Val}; use isla_lib::ir_lexer::new_ir_lexer; use isla_lib::ir_parser; +use isla_lib::memory::Memory; +use std::sync::Arc; #[derive(Parser)] struct Options { @@ -30,6 +35,10 @@ struct Options { #[clap(long)] arch: PathBuf, + /// ISA config file. + #[clap(long)] + isa_config: PathBuf, + /// Specify an input file to be used. Use '-' for stdin. file: PathBuf, } @@ -55,7 +64,21 @@ fn main() -> anyhow::Result<()> { // Parse ISLA Architecture. let contents = read_to_string(&options.arch)?; let mut symtab = Symtab::new(); - let arch = parse_ir::(&contents, &mut symtab)?; + let mut arch = parse_ir::(&contents, &mut symtab)?; + + // ISLA ISA Config. + let mut hasher = Sha256::new(); + let type_info = IRTypeInfo::new(&arch); + let isa_config = match ISAConfig::::from_file( + &mut hasher, + &options.isa_config, + None, + &symtab, + &type_info, + ) { + Ok(isa_config) => isa_config, + Err(msg) => return Err(anyhow::Error::msg(msg)), + }; // Compile functions. for (func, _) in test_file.functions { @@ -64,57 +87,61 @@ fn main() -> anyhow::Result<()> { let _compiled_code = context .compile_and_emit(isa, &mut mem, &mut Default::default()) .map_err(|err| anyhow::anyhow!("{}", pretty_error(&err.func, err.inner)))?; - trace_function(&mem, &arch); + trace_function( + &mem, + &mut arch, + symtab.clone(), + type_info.clone(), + &isa_config, + ); } Ok(()) } -fn trace_function(mc: &[u8], arch: &Vec>) { - // &mut arch, - // symtab, - - // type_info, - let _type_info = IRTypeInfo::new(&arch); - - // TODO: &isa_config, - // TODO: assertion_mode, - // TODO: use_model_reg_init, - - //let iarch = initialize_architecture( - // &mut arch, - // symtab, - // type_info, - // &isa_config, - // assertion_mode, - // use_model_reg_init, - //); - - // let function_id = shared_state.symtab.lookup(&footprint_function); - // let (args, ret_ty, instrs) = shared_state.functions.get(&function_id).unwrap(); - // let task_state = TaskState::new().with_reset_registers(reset_registers); - // let mut task = LocalFrame::new( - // function_id, - // args, - // ret_ty, - // Some(&[opcode_val.clone()]), - // instrs, - // ) - // .add_lets(lets) - // .add_regs(regs) - // .set_memory(memory) - // .task_with_checkpoint(0, &task_state, initial_checkpoint); +fn trace_function( + mc: &[u8], + arch: &mut Vec>, + symtab: Symtab, + type_info: IRTypeInfo, + isa_config: &ISAConfig, +) { + let use_model_reg_init = true; + let iarch = initialize_architecture( + arch, + symtab, + type_info, + &isa_config, + AssertionMode::Optimistic, + use_model_reg_init, + ); + let shared_state = &&iarch.shared_state; + + let opcode = Val::Bits(B::from_bytes(mc)); + + let footprint_function = "zisla_footprint"; + let function_id = shared_state.symtab.lookup(&footprint_function); + let (args, ret_ty, instrs) = shared_state.functions.get(&function_id).unwrap(); + let memory = Memory::new(); + let task_state = TaskState::::new(); + let initial_checkpoint = Checkpoint::new(); + let task = LocalFrame::new(function_id, args, ret_ty, Some(&[opcode]), instrs) + .add_lets(&iarch.lets) + .add_regs(&iarch.regs) + .set_memory(memory) + .task_with_checkpoint(0, &task_state, initial_checkpoint); // task.set_stop_conditions(&stop_conditions); - // let num_threads = 1; - // executor::start_multi( - // num_threads, - // None, - // vec![task], - // shared_state, - // queue.clone(), - // &executor::trace_collector, - // ); + let num_threads = 1; + let queue = Arc::new(SegQueue::new()); + executor::start_multi( + num_threads, + None, + vec![task], + shared_state, + queue.clone(), + &executor::trace_collector, + ); } fn parse_ir<'a, 'input, B: BV>( From 25e85ba601facbb2c8c7bf9e6eda30130eda4455 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Thu, 30 Nov 2023 14:15:17 -0500 Subject: [PATCH 04/73] get smt out --- cranelift/isle/veri/veri_engine/src/isla.rs | 81 ++++++++++++++++----- 1 file changed, 64 insertions(+), 17 deletions(-) diff --git a/cranelift/isle/veri/veri_engine/src/isla.rs b/cranelift/isle/veri/veri_engine/src/isla.rs index 47adef3c051a..508b8544feb0 100644 --- a/cranelift/isle/veri/veri_engine/src/isla.rs +++ b/cranelift/isle/veri/veri_engine/src/isla.rs @@ -3,22 +3,23 @@ use clap::Parser; use cranelift_codegen::print_errors::pretty_error; use cranelift_codegen::Context; use cranelift_reader::{parse_sets_and_triple, parse_test, ParseOptions}; -use isla_lib::config::ISAConfig; -use isla_lib::smt::Checkpoint; -use sha2::{Digest, Sha256}; -use std::fs::File; -use std::io::{self, Read}; -use std::path::{Path, PathBuf}; - use crossbeam::queue::SegQueue; -use isla_lib::bitvector::b64::B64; -use isla_lib::bitvector::BV; +use isla_lib::bitvector::{b129::B129, BV}; +use isla_lib::config::ISAConfig; +use isla_lib::error::IslaError; use isla_lib::executor::{self, LocalFrame, TaskState}; use isla_lib::init::initialize_architecture; use isla_lib::ir::{AssertionMode, Def, IRTypeInfo, Name, Symtab, Val}; use isla_lib::ir_lexer::new_ir_lexer; use isla_lib::ir_parser; use isla_lib::memory::Memory; +use isla_lib::simplify::{self, WriteOpts}; +use isla_lib::smt::{self, Checkpoint, Event, Solver}; +use sha2::{Digest, Sha256}; +use std::fs::File; +use std::io::prelude::*; +use std::io::{self, BufWriter, Read}; +use std::path::{Path, PathBuf}; use std::sync::Arc; #[derive(Parser)] @@ -64,12 +65,12 @@ fn main() -> anyhow::Result<()> { // Parse ISLA Architecture. let contents = read_to_string(&options.arch)?; let mut symtab = Symtab::new(); - let mut arch = parse_ir::(&contents, &mut symtab)?; + let mut arch = parse_ir::(&contents, &mut symtab)?; // ISLA ISA Config. let mut hasher = Sha256::new(); let type_info = IRTypeInfo::new(&arch); - let isa_config = match ISAConfig::::from_file( + let isa_config = match ISAConfig::::from_file( &mut hasher, &options.isa_config, None, @@ -93,7 +94,7 @@ fn main() -> anyhow::Result<()> { symtab.clone(), type_info.clone(), &isa_config, - ); + )?; } Ok(()) @@ -105,7 +106,7 @@ fn trace_function( symtab: Symtab, type_info: IRTypeInfo, isa_config: &ISAConfig, -) { +) -> anyhow::Result<()> { let use_model_reg_init = true; let iarch = initialize_architecture( arch, @@ -117,20 +118,25 @@ fn trace_function( ); let shared_state = &&iarch.shared_state; - let opcode = Val::Bits(B::from_bytes(mc)); + let initial_checkpoint = Checkpoint::new(); + let solver_cfg = smt::Config::new(); + let solver_ctx = smt::Context::new(solver_cfg); + let mut solver = Solver::from_checkpoint(&solver_ctx, initial_checkpoint); + let checkpoint = smt::checkpoint(&mut solver); + + let opcode = mc[..4].try_into().expect("machine code has wrong length"); + let opcode = Val::Bits(B::from_u32(u32::from_le_bytes(opcode))); let footprint_function = "zisla_footprint"; let function_id = shared_state.symtab.lookup(&footprint_function); let (args, ret_ty, instrs) = shared_state.functions.get(&function_id).unwrap(); let memory = Memory::new(); let task_state = TaskState::::new(); - let initial_checkpoint = Checkpoint::new(); let task = LocalFrame::new(function_id, args, ret_ty, Some(&[opcode]), instrs) .add_lets(&iarch.lets) .add_regs(&iarch.regs) .set_memory(memory) - .task_with_checkpoint(0, &task_state, initial_checkpoint); - // task.set_stop_conditions(&stop_conditions); + .task_with_checkpoint(0, &task_state, checkpoint); let num_threads = 1; let queue = Arc::new(SegQueue::new()); @@ -142,6 +148,47 @@ fn trace_function( queue.clone(), &executor::trace_collector, ); + + loop { + match queue.pop() { + Some(Ok((_, mut events))) => { + simplify::hide_initialization(&mut events); + simplify::remove_unused(&mut events); + simplify::propagate_forwards_used_once(&mut events); + simplify::commute_extract(&mut events); + simplify::eval(&mut events); + + let events: Vec> = events.drain(..).rev().collect(); + let stdout = std::io::stdout(); + // Traces can be large, so use a 5MB buffer + let mut handle = BufWriter::with_capacity(5 * usize::pow(2, 20), stdout.lock()); + let write_opts = WriteOpts::default(); + simplify::write_events_with_opts(&mut handle, &events, &shared_state, &write_opts) + .unwrap(); + handle.flush().unwrap() + } + + // Error during execution + Some(Err(err)) => { + let msg = format!("{}", err); + eprintln!( + "{}", + err.source_loc().message::( + None, + shared_state.symtab.files(), + &msg, + true, + true + ) + ); + anyhow::bail!("{}", err); + } + // Empty queue + None => break, + } + } + + Ok(()) } fn parse_ir<'a, 'input, B: BV>( From aa70c442d1c0dfcdfbc2b9ab7af57aba7a5b7fcc Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Thu, 30 Nov 2023 15:37:05 -0500 Subject: [PATCH 05/73] trying to get multiple opcodes to work --- cranelift/isle/veri/veri_engine/src/isla.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/cranelift/isle/veri/veri_engine/src/isla.rs b/cranelift/isle/veri/veri_engine/src/isla.rs index 508b8544feb0..f21bebf9c4c7 100644 --- a/cranelift/isle/veri/veri_engine/src/isla.rs +++ b/cranelift/isle/veri/veri_engine/src/isla.rs @@ -124,15 +124,15 @@ fn trace_function( let mut solver = Solver::from_checkpoint(&solver_ctx, initial_checkpoint); let checkpoint = smt::checkpoint(&mut solver); - let opcode = mc[..4].try_into().expect("machine code has wrong length"); - let opcode = Val::Bits(B::from_u32(u32::from_le_bytes(opcode))); + let opcode_vals = opcode_vals(mc)?; + print!("opcode vals = {:?}", opcode_vals); let footprint_function = "zisla_footprint"; let function_id = shared_state.symtab.lookup(&footprint_function); let (args, ret_ty, instrs) = shared_state.functions.get(&function_id).unwrap(); let memory = Memory::new(); let task_state = TaskState::::new(); - let task = LocalFrame::new(function_id, args, ret_ty, Some(&[opcode]), instrs) + let task = LocalFrame::new(function_id, args, ret_ty, Some(&opcode_vals), instrs) .add_lets(&iarch.lets) .add_regs(&iarch.regs) .set_memory(memory) @@ -160,7 +160,6 @@ fn trace_function( let events: Vec> = events.drain(..).rev().collect(); let stdout = std::io::stdout(); - // Traces can be large, so use a 5MB buffer let mut handle = BufWriter::with_capacity(5 * usize::pow(2, 20), stdout.lock()); let write_opts = WriteOpts::default(); simplify::write_events_with_opts(&mut handle, &events, &shared_state, &write_opts) @@ -191,6 +190,17 @@ fn trace_function( Ok(()) } +fn opcode_vals(mc: &[u8]) -> anyhow::Result>> { + let mut vals = Vec::new(); + for opcode_bytes in mc.chunks(4) { + let val = Val::Bits(B::from_u32(u32::from_le_bytes( + opcode_bytes.try_into().unwrap(), + ))); + vals.push(val); + } + Ok(vals) +} + fn parse_ir<'a, 'input, B: BV>( contents: &'input str, symtab: &'a mut Symtab<'input>, From 7c432e0705a3db97c0135f5b3a2fc42134140360 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Thu, 30 Nov 2023 18:55:20 -0500 Subject: [PATCH 06/73] emit Inst to opcodes --- cranelift/codegen/src/isa/aarch64/inst/mod.rs | 6 +-- cranelift/codegen/src/lib.rs | 2 +- cranelift/isle/veri/veri_engine/Cargo.toml | 4 ++ cranelift/isle/veri/veri_engine/src/emit.rs | 38 +++++++++++++++++++ 4 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 cranelift/isle/veri/veri_engine/src/emit.rs diff --git a/cranelift/codegen/src/isa/aarch64/inst/mod.rs b/cranelift/codegen/src/isa/aarch64/inst/mod.rs index e916d9e72359..b510fa9bd29f 100644 --- a/cranelift/codegen/src/isa/aarch64/inst/mod.rs +++ b/cranelift/codegen/src/isa/aarch64/inst/mod.rs @@ -15,14 +15,14 @@ use smallvec::{smallvec, SmallVec}; use std::fmt::Write; use std::string::{String, ToString}; -pub(crate) mod regs; -pub(crate) use self::regs::*; +pub mod regs; +pub use self::regs::*; pub mod imms; pub use self::imms::*; pub mod args; pub use self::args::*; pub mod emit; -pub(crate) use self::emit::*; +pub use self::emit::*; use crate::isa::aarch64::abi::AArch64MachineDeps; pub(crate) mod unwind; diff --git a/cranelift/codegen/src/lib.rs b/cranelift/codegen/src/lib.rs index c856e1a1b645..b95a75e3f70f 100644 --- a/cranelift/codegen/src/lib.rs +++ b/cranelift/codegen/src/lib.rs @@ -1,5 +1,5 @@ //! Cranelift code generation library. -#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)] +#![deny(trivial_numeric_casts, unused_extern_crates)] #![warn(unused_import_braces)] #![cfg_attr(feature = "std", deny(unstable_features))] #![no_std] diff --git a/cranelift/isle/veri/veri_engine/Cargo.toml b/cranelift/isle/veri/veri_engine/Cargo.toml index 5023ef266ee6..361a85c2d8c3 100644 --- a/cranelift/isle/veri/veri_engine/Cargo.toml +++ b/cranelift/isle/veri/veri_engine/Cargo.toml @@ -17,6 +17,10 @@ path = "src/main.rs" name = "isla" path = "src/isla.rs" +[[bin]] +name = "emit" +path = "src/emit.rs" + [dependencies] cranelift-isle = { path = "../../isle" } cranelift-codegen = { path = "../../../codegen" } diff --git a/cranelift/isle/veri/veri_engine/src/emit.rs b/cranelift/isle/veri/veri_engine/src/emit.rs new file mode 100644 index 000000000000..aad5229c8b84 --- /dev/null +++ b/cranelift/isle/veri/veri_engine/src/emit.rs @@ -0,0 +1,38 @@ +use cranelift_codegen::isa::aarch64::inst::*; +use cranelift_codegen::settings; +use cranelift_codegen::MachBuffer; +use cranelift_codegen::MachInstEmit; + +fn main() -> anyhow::Result<()> { + let inst = Inst::AluRRR { + alu_op: ALUOp::Add, + size: OperandSize::Size64, + rd: writable_xreg(4), + rn: xreg(5), + rm: xreg(6), + }; + + let opcodes = opcodes(&inst); + println!("opcode = {:?}", opcodes); + + Ok(()) +} + +fn assemble(inst: &Inst) -> Vec { + let flags = settings::Flags::new(settings::builder()); + let emit_info = EmitInfo::new(flags); + let mut buffer = MachBuffer::new(); + inst.emit(&[], &mut buffer, &emit_info, &mut Default::default()); + let buffer = buffer.finish(&Default::default(), &mut Default::default()); + return buffer.data().to_vec(); +} + +fn opcodes(inst: &Inst) -> Vec { + let machine_code = assemble(&inst); + let mut opcodes = Vec::new(); + for opcode_bytes in machine_code.chunks(4) { + assert_eq!(opcode_bytes.len(), 4); + opcodes.push(u32::from_le_bytes(opcode_bytes.try_into().unwrap())); + } + opcodes +} From 8a9082e1c3b77a399307335088cddc86eb00d496 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Thu, 30 Nov 2023 19:18:10 -0500 Subject: [PATCH 07/73] Inst to ISLA trace --- cranelift/isle/veri/veri_engine/src/emit.rs | 180 ++++++++++++++++++++ 1 file changed, 180 insertions(+) diff --git a/cranelift/isle/veri/veri_engine/src/emit.rs b/cranelift/isle/veri/veri_engine/src/emit.rs index aad5229c8b84..aca0b876c423 100644 --- a/cranelift/isle/veri/veri_engine/src/emit.rs +++ b/cranelift/isle/veri/veri_engine/src/emit.rs @@ -1,9 +1,62 @@ +use anyhow::Context as _; +use clap::Parser; use cranelift_codegen::isa::aarch64::inst::*; use cranelift_codegen::settings; use cranelift_codegen::MachBuffer; use cranelift_codegen::MachInstEmit; +use crossbeam::queue::SegQueue; +use isla_lib::bitvector::{b129::B129, BV}; +use isla_lib::config::ISAConfig; +use isla_lib::error::IslaError; +use isla_lib::executor::{self, LocalFrame, TaskState}; +use isla_lib::init::initialize_architecture; +use isla_lib::ir::{AssertionMode, Def, IRTypeInfo, Name, Symtab, Val}; +use isla_lib::ir_lexer::new_ir_lexer; +use isla_lib::ir_parser; +use isla_lib::memory::Memory; +use isla_lib::simplify::{self, WriteOpts}; +use isla_lib::smt::{self, Checkpoint, Event, Solver}; +use sha2::{Digest, Sha256}; +use std::fs::File; +use std::io::prelude::*; +use std::io::{self, BufWriter, Read}; +use std::path::{Path, PathBuf}; +use std::sync::Arc; + +#[derive(Parser)] +struct Options { + /// Architecture definition. + #[clap(long)] + arch: PathBuf, + + /// ISA config file. + #[clap(long)] + isa_config: PathBuf, +} fn main() -> anyhow::Result<()> { + let options = Options::parse(); + + // Parse ISLA Architecture. + let contents = read_to_string(&options.arch)?; + let mut symtab = Symtab::new(); + let mut arch = parse_ir::(&contents, &mut symtab)?; + + // ISLA ISA Config. + let mut hasher = Sha256::new(); + let type_info = IRTypeInfo::new(&arch); + let isa_config = match ISAConfig::::from_file( + &mut hasher, + &options.isa_config, + None, + &symtab, + &type_info, + ) { + Ok(isa_config) => isa_config, + Err(msg) => return Err(anyhow::Error::msg(msg)), + }; + + // Assemble an instruction. let inst = Inst::AluRRR { alu_op: ALUOp::Add, size: OperandSize::Size64, @@ -15,6 +68,16 @@ fn main() -> anyhow::Result<()> { let opcodes = opcodes(&inst); println!("opcode = {:?}", opcodes); + // ISLA trace. + assert_eq!(opcodes.len(), 1); + trace_opcode( + opcodes[0], + &mut arch, + symtab.clone(), + type_info.clone(), + &isa_config, + )?; + Ok(()) } @@ -36,3 +99,120 @@ fn opcodes(inst: &Inst) -> Vec { } opcodes } + +fn trace_opcode( + opcode: u32, + arch: &mut Vec>, + symtab: Symtab, + type_info: IRTypeInfo, + isa_config: &ISAConfig, +) -> anyhow::Result<()> { + let use_model_reg_init = true; + let iarch = initialize_architecture( + arch, + symtab, + type_info, + &isa_config, + AssertionMode::Optimistic, + use_model_reg_init, + ); + let shared_state = &&iarch.shared_state; + + let initial_checkpoint = Checkpoint::new(); + let solver_cfg = smt::Config::new(); + let solver_ctx = smt::Context::new(solver_cfg); + let mut solver = Solver::from_checkpoint(&solver_ctx, initial_checkpoint); + let checkpoint = smt::checkpoint(&mut solver); + + let opcode_val = Val::Bits(B::from_u32(opcode)); + + let footprint_function = "zisla_footprint"; + let function_id = shared_state.symtab.lookup(&footprint_function); + let (args, ret_ty, instrs) = shared_state.functions.get(&function_id).unwrap(); + let memory = Memory::new(); + let task_state = TaskState::::new(); + let task = LocalFrame::new(function_id, args, ret_ty, Some(&[opcode_val]), instrs) + .add_lets(&iarch.lets) + .add_regs(&iarch.regs) + .set_memory(memory) + .task_with_checkpoint(0, &task_state, checkpoint); + + let num_threads = 1; + let queue = Arc::new(SegQueue::new()); + executor::start_multi( + num_threads, + None, + vec![task], + shared_state, + queue.clone(), + &executor::trace_collector, + ); + + loop { + match queue.pop() { + Some(Ok((_, mut events))) => { + simplify::hide_initialization(&mut events); + simplify::remove_unused(&mut events); + simplify::propagate_forwards_used_once(&mut events); + simplify::commute_extract(&mut events); + simplify::eval(&mut events); + + let events: Vec> = events.drain(..).rev().collect(); + let stdout = std::io::stdout(); + let mut handle = BufWriter::with_capacity(5 * usize::pow(2, 20), stdout.lock()); + let write_opts = WriteOpts::default(); + simplify::write_events_with_opts(&mut handle, &events, &shared_state, &write_opts) + .unwrap(); + handle.flush().unwrap() + } + + // Error during execution + Some(Err(err)) => { + let msg = format!("{}", err); + eprintln!( + "{}", + err.source_loc().message::( + None, + shared_state.symtab.files(), + &msg, + true, + true + ) + ); + anyhow::bail!("{}", err); + } + // Empty queue + None => break, + } + } + + Ok(()) +} + +fn parse_ir<'a, 'input, B: BV>( + contents: &'input str, + symtab: &'a mut Symtab<'input>, +) -> anyhow::Result>> { + match ir_parser::IrParser::new().parse(symtab, new_ir_lexer(&contents)) { + Ok(ir) => Ok(ir), + Err(_) => Err(anyhow::Error::msg("bad")), + } +} + +/// Read an entire file into a string. +fn read_to_string>(path: P) -> anyhow::Result { + let mut buffer = String::new(); + let path = path.as_ref(); + if path == Path::new("-") { + let stdin = io::stdin(); + let mut stdin = stdin.lock(); + stdin + .read_to_string(&mut buffer) + .context("failed to read stdin to string")?; + } else { + let mut file = File::open(path)?; + file.read_to_string(&mut buffer) + .with_context(|| format!("failed to read {} to string", path.display()))?; + } + Ok(buffer) +} From 943bd86440214dc7edea0f7e56695ffc6aefd264 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Thu, 30 Nov 2023 20:35:26 -0500 Subject: [PATCH 08/73] anyhow::bail --- cranelift/isle/veri/veri_engine/src/emit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cranelift/isle/veri/veri_engine/src/emit.rs b/cranelift/isle/veri/veri_engine/src/emit.rs index aca0b876c423..acc361c714d7 100644 --- a/cranelift/isle/veri/veri_engine/src/emit.rs +++ b/cranelift/isle/veri/veri_engine/src/emit.rs @@ -53,7 +53,7 @@ fn main() -> anyhow::Result<()> { &type_info, ) { Ok(isa_config) => isa_config, - Err(msg) => return Err(anyhow::Error::msg(msg)), + Err(msg) => anyhow::bail!(msg), }; // Assemble an instruction. From 173bb50674dbd549d3b1efe96f313fe5600367cf Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Sun, 10 Dec 2023 13:21:33 -0500 Subject: [PATCH 09/73] veri: slight refactor isla emit --- Cargo.lock | 2 +- cranelift/isle/veri/veri_engine/Cargo.toml | 2 +- cranelift/isle/veri/veri_engine/src/emit.rs | 70 ++++++++++----------- 3 files changed, 37 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 06b415cb282a..477765983f7c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1790,7 +1790,7 @@ dependencies = [ [[package]] name = "isla-lib" version = "0.2.0" -source = "git+https://github.com/rems-project/isla.git#b8e614bda4a20e42c37d8b216853653133d04322" +source = "git+https://github.com/rems-project/isla.git?rev=4134411c0f463807edd788f67b3db34c1899d9b6#4134411c0f463807edd788f67b3db34c1899d9b6" dependencies = [ "ahash 0.7.7", "bincode", diff --git a/cranelift/isle/veri/veri_engine/Cargo.toml b/cranelift/isle/veri/veri_engine/Cargo.toml index 361a85c2d8c3..7569fde1a686 100644 --- a/cranelift/isle/veri/veri_engine/Cargo.toml +++ b/cranelift/isle/veri/veri_engine/Cargo.toml @@ -26,7 +26,7 @@ cranelift-isle = { path = "../../isle" } cranelift-codegen = { path = "../../../codegen" } cranelift-reader = { path = "../../../reader" } cranelift-codegen-meta = { path = "../../../codegen/meta" } -isla-lib = { git = "https://github.com/rems-project/isla.git" } +isla-lib = { git = "https://github.com/rems-project/isla.git", rev = "4134411c0f463807edd788f67b3db34c1899d9b6" } anyhow = { workspace = true } veri_ir = { path = "../veri_ir" } easy-smt = { git = "https://github.com/elliottt/easy-smt.git" } diff --git a/cranelift/isle/veri/veri_engine/src/emit.rs b/cranelift/isle/veri/veri_engine/src/emit.rs index acc361c714d7..327dfd92b1bd 100644 --- a/cranelift/isle/veri/veri_engine/src/emit.rs +++ b/cranelift/isle/veri/veri_engine/src/emit.rs @@ -5,11 +5,11 @@ use cranelift_codegen::settings; use cranelift_codegen::MachBuffer; use cranelift_codegen::MachInstEmit; use crossbeam::queue::SegQueue; -use isla_lib::bitvector::{b129::B129, BV}; +use isla_lib::bitvector::{b64::B64, BV}; use isla_lib::config::ISAConfig; use isla_lib::error::IslaError; use isla_lib::executor::{self, LocalFrame, TaskState}; -use isla_lib::init::initialize_architecture; +use isla_lib::init::{initialize_architecture, Initialized}; use isla_lib::ir::{AssertionMode, Def, IRTypeInfo, Name, Symtab, Val}; use isla_lib::ir_lexer::new_ir_lexer; use isla_lib::ir_parser; @@ -40,12 +40,12 @@ fn main() -> anyhow::Result<()> { // Parse ISLA Architecture. let contents = read_to_string(&options.arch)?; let mut symtab = Symtab::new(); - let mut arch = parse_ir::(&contents, &mut symtab)?; + let mut arch = parse_ir::(&contents, &mut symtab)?; // ISLA ISA Config. let mut hasher = Sha256::new(); let type_info = IRTypeInfo::new(&arch); - let isa_config = match ISAConfig::::from_file( + let isa_config = match ISAConfig::::from_file( &mut hasher, &options.isa_config, None, @@ -56,6 +56,17 @@ fn main() -> anyhow::Result<()> { Err(msg) => anyhow::bail!(msg), }; + let use_model_reg_init = true; + let iarch = initialize_architecture( + &mut arch, + symtab, + type_info, + &isa_config, + AssertionMode::Optimistic, + use_model_reg_init, + ); + let shared_state = &&iarch.shared_state; + // Assemble an instruction. let inst = Inst::AluRRR { alu_op: ALUOp::Add, @@ -66,17 +77,19 @@ fn main() -> anyhow::Result<()> { }; let opcodes = opcodes(&inst); - println!("opcode = {:?}", opcodes); + assert_eq!(opcodes.len(), 1); // ISLA trace. - assert_eq!(opcodes.len(), 1); - trace_opcode( - opcodes[0], - &mut arch, - symtab.clone(), - type_info.clone(), - &isa_config, - )?; + let paths = trace_opcode(opcodes[0], &iarch)?; + + // Dump. + for events in paths { + let stdout = std::io::stdout(); + let mut handle = BufWriter::with_capacity(5 * usize::pow(2, 20), stdout.lock()); + let write_opts = WriteOpts::default(); + simplify::write_events_with_opts(&mut handle, &events, &shared_state, &write_opts).unwrap(); + handle.flush().unwrap(); + } Ok(()) } @@ -100,22 +113,10 @@ fn opcodes(inst: &Inst) -> Vec { opcodes } -fn trace_opcode( +fn trace_opcode<'ir, B: BV>( opcode: u32, - arch: &mut Vec>, - symtab: Symtab, - type_info: IRTypeInfo, - isa_config: &ISAConfig, -) -> anyhow::Result<()> { - let use_model_reg_init = true; - let iarch = initialize_architecture( - arch, - symtab, - type_info, - &isa_config, - AssertionMode::Optimistic, - use_model_reg_init, - ); + iarch: &'ir Initialized<'ir, B>, +) -> anyhow::Result>>> { let shared_state = &&iarch.shared_state; let initial_checkpoint = Checkpoint::new(); @@ -148,22 +149,21 @@ fn trace_opcode( &executor::trace_collector, ); + let mut paths = Vec::new(); loop { match queue.pop() { Some(Ok((_, mut events))) => { simplify::hide_initialization(&mut events); + simplify::remove_extra_register_fields(&mut events); + simplify::remove_repeated_register_reads(&mut events); + simplify::remove_unused_register_assumptions(&mut events); simplify::remove_unused(&mut events); simplify::propagate_forwards_used_once(&mut events); simplify::commute_extract(&mut events); simplify::eval(&mut events); let events: Vec> = events.drain(..).rev().collect(); - let stdout = std::io::stdout(); - let mut handle = BufWriter::with_capacity(5 * usize::pow(2, 20), stdout.lock()); - let write_opts = WriteOpts::default(); - simplify::write_events_with_opts(&mut handle, &events, &shared_state, &write_opts) - .unwrap(); - handle.flush().unwrap() + paths.push(events); } // Error during execution @@ -186,7 +186,7 @@ fn trace_opcode( } } - Ok(()) + Ok(paths) } fn parse_ir<'a, 'input, B: BV>( From 565f70f0e6729ccb6cbff633e19e38a51cb29536 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Wed, 13 Dec 2023 19:43:26 -0500 Subject: [PATCH 10/73] veri: isla emit tree shake --- cranelift/isle/veri/veri_engine/src/emit.rs | 235 +++++++++++++++++++- 1 file changed, 229 insertions(+), 6 deletions(-) diff --git a/cranelift/isle/veri/veri_engine/src/emit.rs b/cranelift/isle/veri/veri_engine/src/emit.rs index 327dfd92b1bd..c69a29dccbc4 100644 --- a/cranelift/isle/veri/veri_engine/src/emit.rs +++ b/cranelift/isle/veri/veri_engine/src/emit.rs @@ -15,8 +15,10 @@ use isla_lib::ir_lexer::new_ir_lexer; use isla_lib::ir_parser; use isla_lib::memory::Memory; use isla_lib::simplify::{self, WriteOpts}; +use isla_lib::smt::smtlib; use isla_lib::smt::{self, Checkpoint, Event, Solver}; use sha2::{Digest, Sha256}; +use std::collections::{HashMap, HashSet}; use std::fs::File; use std::io::prelude::*; use std::io::{self, BufWriter, Read}; @@ -65,7 +67,6 @@ fn main() -> anyhow::Result<()> { AssertionMode::Optimistic, use_model_reg_init, ); - let shared_state = &&iarch.shared_state; // Assemble an instruction. let inst = Inst::AluRRR { @@ -84,11 +85,8 @@ fn main() -> anyhow::Result<()> { // Dump. for events in paths { - let stdout = std::io::stdout(); - let mut handle = BufWriter::with_capacity(5 * usize::pow(2, 20), stdout.lock()); - let write_opts = WriteOpts::default(); - simplify::write_events_with_opts(&mut handle, &events, &shared_state, &write_opts).unwrap(); - handle.flush().unwrap(); + let filtered = tree_shake(&events); + write_events(&filtered, &iarch)?; } Ok(()) @@ -189,6 +187,231 @@ fn trace_opcode<'ir, B: BV>( Ok(paths) } +fn event_writes(event: &Event) -> Option { + match event { + Event::Smt(def, _, _) => match def { + smtlib::Def::DefineConst(v, _) => Some(*v), + _ => None, + }, + Event::ReadReg(_, _, val) => match val { + Val::Symbolic(sym) => Some(*sym), + _ => None, + }, + _ => None, + } +} + +fn defns(events: &Vec>) -> HashMap { + let mut defn_idx = HashMap::new(); + for (i, event) in events.iter().enumerate() { + if let Some(sym) = event_writes(event) { + defn_idx.insert(sym, i); + } + } + defn_idx +} + +fn exp_uses(exp: &smtlib::Exp) -> HashSet { + use smtlib::Exp::*; + match exp { + Var(sym) => HashSet::from([*sym]), + //Bits(_) | Bits64(_) | Enum(_) | Bool(_) | FPConstant(..) | FPRoundingMode(_) => (), + Not(exp) + | Bvnot(exp) + | Bvneg(exp) + | Extract(_, _, exp) + | ZeroExtend(_, exp) + | SignExtend(_, exp) + | FPUnary(_, exp) => exp_uses(exp), + Eq(lhs, rhs) + | Neq(lhs, rhs) + | And(lhs, rhs) + | Or(lhs, rhs) + | Bvand(lhs, rhs) + | Bvor(lhs, rhs) + | Bvxor(lhs, rhs) + | Bvnand(lhs, rhs) + | Bvnor(lhs, rhs) + | Bvxnor(lhs, rhs) + | Bvadd(lhs, rhs) + | Bvsub(lhs, rhs) + | Bvmul(lhs, rhs) + | Bvudiv(lhs, rhs) + | Bvsdiv(lhs, rhs) + | Bvurem(lhs, rhs) + | Bvsrem(lhs, rhs) + | Bvsmod(lhs, rhs) + | Bvult(lhs, rhs) + | Bvslt(lhs, rhs) + | Bvule(lhs, rhs) + | Bvsle(lhs, rhs) + | Bvuge(lhs, rhs) + | Bvsge(lhs, rhs) + | Bvugt(lhs, rhs) + | Bvsgt(lhs, rhs) + | Bvshl(lhs, rhs) + | Bvlshr(lhs, rhs) + | Bvashr(lhs, rhs) + | Concat(lhs, rhs) + | FPBinary(_, lhs, rhs) => { + let lhs_uses = exp_uses(lhs); + let rhs_uses = exp_uses(rhs); + &lhs_uses | &rhs_uses + } + //Ite(cond, then_exp, else_exp) => { + // uses_in_exp(uses, cond); + // uses_in_exp(uses, then_exp); + // uses_in_exp(uses, else_exp) + //} + //App(f, args) => { + // uses.insert(*f, uses.get(f).unwrap_or(&0) + 1); + // for arg in args { + // uses_in_exp(uses, arg); + // } + //} + //Select(array, index) => { + // uses_in_exp(uses, array); + // uses_in_exp(uses, index) + //} + //Store(array, index, val) => { + // uses_in_exp(uses, array); + // uses_in_exp(uses, index); + // uses_in_exp(uses, val) + //} + //Distinct(exps) => { + // for exp in exps { + // uses_in_exp(uses, exp); + // } + //} + //FPRoundingUnary(_, rm, exp) => { + // uses_in_exp(uses, rm); + // uses_in_exp(uses, exp); + //} + //FPRoundingBinary(_, rm, lhs, rhs) => { + // uses_in_exp(uses, rm); + // uses_in_exp(uses, lhs); + // uses_in_exp(uses, rhs) + //} + //FPfma(rm, x, y, z) => { + // uses_in_exp(uses, rm); + // uses_in_exp(uses, x); + // uses_in_exp(uses, y); + // uses_in_exp(uses, z) + //} + _ => HashSet::new(), + } +} + +fn smt_def_uses(def: &smtlib::Def) -> HashSet { + match def { + // DeclareConst(Sym, Ty), + // DeclareFun(Sym, Vec, Ty), + smtlib::Def::DefineConst(_, exp) => exp_uses(&exp), + // DefineEnum(Name, usize), + // Assert(Exp), + _ => HashSet::new(), + } +} + +fn val_uses(val: &Val) -> HashSet { + // See: simplify::uses_in_value + match val { + Val::Symbolic(sym) => HashSet::from([*sym]), + // MixedBits(segments) => segments.iter().for_each(|segment| match segment { + // BitsSegment::Symbolic(v) => { + // uses.insert(*v, uses.get(v).unwrap_or(&0) + 1); + // } + // BitsSegment::Concrete(_) => (), + // }), + // I64(_) | I128(_) | Bool(_) | Bits(_) | Enum(_) | String(_) | Unit | Ref(_) | Poison => (), + // List(vals) | Vector(vals) => vals.iter().for_each(|val| uses_in_value(uses, val)), + // Struct(fields) => fields.iter().for_each(|(_, val)| uses_in_value(uses, val)), + // Ctor(_, val) => uses_in_value(uses, val), + // SymbolicCtor(v, possibilities) => { + // uses.insert(*v, uses.get(v).unwrap_or(&0) + 1); + // possibilities + // .iter() + // .for_each(|(_, val)| uses_in_value(uses, val)) + // } + _ => HashSet::new(), + } +} + +fn uses(event: &Event) -> HashSet { + match event { + Event::Smt(def, _, _) => smt_def_uses(&def), + Event::WriteReg(_, _, val) => val_uses(val), + _ => HashSet::new(), + } +} + +fn tree_shake(events: &Vec>) -> Vec> { + // Definitions. + let defn_idx = defns(events); + + // Work list: populate with register writes. + let mut work_list = Vec::new(); + let mut live = HashSet::new(); + for (i, event) in events.iter().enumerate() { + match event { + Event::WriteReg(_, _, val) => match val { + Val::Symbolic(sym) => { + // Mark live. + live.insert(i); + + // Push the variable to be visited. + let d = defn_idx[&sym]; + live.insert(d); + work_list.push(d); + } + _ => continue, + }, + _ => continue, + }; + } + + // Process. + while !work_list.is_empty() { + let i = work_list.pop().unwrap(); + assert!(live.contains(&i), "visited events should be live"); + let event = &events[i]; + + // Mark uses live. + for u in uses(&event) { + // Lookup definition of this dependency. + let ui = defn_idx[&u]; + if live.contains(&ui) { + continue; + } + + live.insert(ui); + work_list.push(ui); + } + } + + events + .iter() + .enumerate() + .filter_map(|(i, event)| if live.contains(&i) { Some(event) } else { None }) + .cloned() + .collect() +} + +fn write_events<'ir, B: BV>( + events: &Vec>, + iarch: &'ir Initialized<'ir, B>, +) -> anyhow::Result<()> { + // Print. + let stdout = std::io::stdout(); + let mut handle = BufWriter::with_capacity(5 * usize::pow(2, 20), stdout.lock()); + let write_opts = WriteOpts::default(); + simplify::write_events_with_opts(&mut handle, &events, &iarch.shared_state, &write_opts) + .unwrap(); + handle.flush().unwrap(); + + Ok(()) +} + fn parse_ir<'a, 'input, B: BV>( contents: &'input str, symtab: &'a mut Symtab<'input>, From 6c1bebf5cc1427ec2c211e0d21510bd329726cea Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Wed, 13 Dec 2023 19:46:40 -0500 Subject: [PATCH 11/73] use todo! --- cranelift/isle/veri/veri_engine/src/emit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cranelift/isle/veri/veri_engine/src/emit.rs b/cranelift/isle/veri/veri_engine/src/emit.rs index c69a29dccbc4..06db57ca3120 100644 --- a/cranelift/isle/veri/veri_engine/src/emit.rs +++ b/cranelift/isle/veri/veri_engine/src/emit.rs @@ -298,7 +298,7 @@ fn exp_uses(exp: &smtlib::Exp) -> HashSet { // uses_in_exp(uses, y); // uses_in_exp(uses, z) //} - _ => HashSet::new(), + _ => todo!(), } } From ee2655c044b641cd5c951103e528983a72ede63c Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Thu, 14 Dec 2023 20:17:27 -0500 Subject: [PATCH 12/73] start adhoc tool to experiment with x64 isla --- cranelift/codegen/src/isa/x64/inst/regs.rs | 6 ++-- cranelift/codegen/src/isa/x64/mod.rs | 2 +- cranelift/isle/veri/veri_engine/Cargo.toml | 4 +++ cranelift/isle/veri/veri_engine/src/x64.rs | 34 ++++++++++++++++++++++ 4 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 cranelift/isle/veri/veri_engine/src/x64.rs diff --git a/cranelift/codegen/src/isa/x64/inst/regs.rs b/cranelift/codegen/src/isa/x64/inst/regs.rs index ce7f1ff72a0b..f564d140c978 100644 --- a/cranelift/codegen/src/isa/x64/inst/regs.rs +++ b/cranelift/codegen/src/isa/x64/inst/regs.rs @@ -51,7 +51,7 @@ pub(crate) fn rax() -> Reg { pub(crate) fn rcx() -> Reg { gpr(ENC_RCX) } -pub(crate) fn rdx() -> Reg { +pub fn rdx() -> Reg { gpr(ENC_RDX) } pub(crate) fn r8() -> Reg { @@ -69,7 +69,7 @@ pub(crate) fn r11() -> Reg { pub(crate) fn r12() -> Reg { gpr(ENC_R12) } -pub(crate) fn r13() -> Reg { +pub fn r13() -> Reg { gpr(ENC_R13) } pub(crate) fn r14() -> Reg { @@ -79,7 +79,7 @@ pub(crate) fn rbx() -> Reg { gpr(ENC_RBX) } -pub(crate) fn r15() -> Reg { +pub fn r15() -> Reg { gpr(ENC_R15) } diff --git a/cranelift/codegen/src/isa/x64/mod.rs b/cranelift/codegen/src/isa/x64/mod.rs index 75fbe2980abb..2a7d63e182c9 100644 --- a/cranelift/codegen/src/isa/x64/mod.rs +++ b/cranelift/codegen/src/isa/x64/mod.rs @@ -22,7 +22,7 @@ use target_lexicon::Triple; mod abi; pub mod encoding; -mod inst; +pub mod inst; mod lower; pub mod settings; diff --git a/cranelift/isle/veri/veri_engine/Cargo.toml b/cranelift/isle/veri/veri_engine/Cargo.toml index 7569fde1a686..203eb6fcd4cd 100644 --- a/cranelift/isle/veri/veri_engine/Cargo.toml +++ b/cranelift/isle/veri/veri_engine/Cargo.toml @@ -21,6 +21,10 @@ path = "src/isla.rs" name = "emit" path = "src/emit.rs" +[[bin]] +name = "x64" +path = "src/x64.rs" + [dependencies] cranelift-isle = { path = "../../isle" } cranelift-codegen = { path = "../../../codegen" } diff --git a/cranelift/isle/veri/veri_engine/src/x64.rs b/cranelift/isle/veri/veri_engine/src/x64.rs new file mode 100644 index 000000000000..5fd17e6c98bf --- /dev/null +++ b/cranelift/isle/veri/veri_engine/src/x64.rs @@ -0,0 +1,34 @@ +use cranelift_codegen::isa::x64::{ + self, + inst::{args::*, *}, +}; +use cranelift_codegen::{settings, MachBuffer, MachInstEmit, Reg, Writable}; + +fn main() -> anyhow::Result<()> { + let rdx = regs::rdx(); + let r13 = regs::r13(); + let w_rdx = Writable::::from_reg(rdx); + let inst = Inst::AluRmiR { + size: OperandSize::Size64, + op: AluRmiROpcode::Add, + src1: Gpr::new(rdx).unwrap(), + src2: GprMemImm::new(RegMemImm::reg(r13)).unwrap(), + dst: WritableGpr::from_writable_reg(w_rdx).unwrap(), + }; + + let machine_code = assemble(&inst); + println!("{:02x?}", machine_code); + + Ok(()) +} + +fn assemble(inst: &Inst) -> Vec { + let flags = settings::Flags::new(settings::builder()); + let isa_flag_builder = x64::settings::builder(); + let isa_flags = x64::settings::Flags::new(&flags, &isa_flag_builder); + let emit_info = EmitInfo::new(flags, isa_flags); + let mut buffer = MachBuffer::new(); + inst.emit(&[], &mut buffer, &emit_info, &mut Default::default()); + let buffer = buffer.finish(&Default::default(), &mut Default::default()); + return buffer.data().to_vec(); +} From d44f3b1493b3dc6c80f2e2f82970a1efc30bb755 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Thu, 14 Dec 2023 20:29:59 -0500 Subject: [PATCH 13/73] copypasta isla logic into x86 --- cranelift/isle/veri/veri_engine/src/x64.rs | 195 ++++++++++++++++++++- 1 file changed, 194 insertions(+), 1 deletion(-) diff --git a/cranelift/isle/veri/veri_engine/src/x64.rs b/cranelift/isle/veri/veri_engine/src/x64.rs index 5fd17e6c98bf..7f8590efde81 100644 --- a/cranelift/isle/veri/veri_engine/src/x64.rs +++ b/cranelift/isle/veri/veri_engine/src/x64.rs @@ -1,10 +1,73 @@ +use anyhow::Context as _; +use clap::Parser; use cranelift_codegen::isa::x64::{ self, inst::{args::*, *}, }; use cranelift_codegen::{settings, MachBuffer, MachInstEmit, Reg, Writable}; +use crossbeam::queue::SegQueue; +use isla_lib::bitvector::{b64::B64, BV}; +use isla_lib::config::ISAConfig; +use isla_lib::error::IslaError; +use isla_lib::executor::{self, LocalFrame, TaskState}; +use isla_lib::init::{initialize_architecture, Initialized}; +use isla_lib::ir::{AssertionMode, Def, IRTypeInfo, Name, Symtab, Val}; +use isla_lib::ir_lexer::new_ir_lexer; +use isla_lib::ir_parser; +use isla_lib::memory::Memory; +use isla_lib::simplify::{self, WriteOpts}; +use isla_lib::smt::{self, Checkpoint, Event, Solver}; +use sha2::{Digest, Sha256}; +use std::fs::File; +use std::io::prelude::*; +use std::io::{self, BufWriter, Read}; +use std::path::{Path, PathBuf}; +use std::sync::Arc; + +#[derive(Parser)] +struct Options { + /// Architecture definition. + #[clap(long)] + arch: PathBuf, + + /// ISA config file. + #[clap(long)] + isa_config: PathBuf, +} fn main() -> anyhow::Result<()> { + let options = Options::parse(); + + // Parse ISLA Architecture. + let contents = read_to_string(&options.arch)?; + let mut symtab = Symtab::new(); + let mut arch = parse_ir::(&contents, &mut symtab)?; + + // ISLA ISA Config. + let mut hasher = Sha256::new(); + let type_info = IRTypeInfo::new(&arch); + let isa_config = match ISAConfig::::from_file( + &mut hasher, + &options.isa_config, + None, + &symtab, + &type_info, + ) { + Ok(isa_config) => isa_config, + Err(msg) => anyhow::bail!(msg), + }; + + let use_model_reg_init = true; + let iarch = initialize_architecture( + &mut arch, + symtab, + type_info, + &isa_config, + AssertionMode::Optimistic, + use_model_reg_init, + ); + + // Assemble x64 instruction. let rdx = regs::rdx(); let r13 = regs::r13(); let w_rdx = Writable::::from_reg(rdx); @@ -17,11 +80,20 @@ fn main() -> anyhow::Result<()> { }; let machine_code = assemble(&inst); - println!("{:02x?}", machine_code); + println!("machine code = {:02x?}", machine_code); + + // ISLA trace. + let paths = trace_opcode(&machine_code, &iarch)?; + + // Dump. + for events in paths { + write_events(&events, &iarch)?; + } Ok(()) } +/// Assemble x64 instruction. fn assemble(inst: &Inst) -> Vec { let flags = settings::Flags::new(settings::builder()); let isa_flag_builder = x64::settings::builder(); @@ -32,3 +104,124 @@ fn assemble(inst: &Inst) -> Vec { let buffer = buffer.finish(&Default::default(), &mut Default::default()); return buffer.data().to_vec(); } + +fn trace_opcode<'ir, B: BV>( + machine_code: &Vec, + iarch: &'ir Initialized<'ir, B>, +) -> anyhow::Result>>> { + let shared_state = &&iarch.shared_state; + + let initial_checkpoint = Checkpoint::new(); + let solver_cfg = smt::Config::new(); + let solver_ctx = smt::Context::new(solver_cfg); + let mut solver = Solver::from_checkpoint(&solver_ctx, initial_checkpoint); + let checkpoint = smt::checkpoint(&mut solver); + + let opcode_val = Val::Bits(B::from_bytes(&machine_code)); + + let footprint_function = "zisla_footprint"; + let function_id = shared_state.symtab.lookup(&footprint_function); + let (args, ret_ty, instrs) = shared_state.functions.get(&function_id).unwrap(); + let memory = Memory::new(); + let task_state = TaskState::::new(); + let task = LocalFrame::new(function_id, args, ret_ty, Some(&[opcode_val]), instrs) + .add_lets(&iarch.lets) + .add_regs(&iarch.regs) + .set_memory(memory) + .task_with_checkpoint(0, &task_state, checkpoint); + + let num_threads = 1; + let queue = Arc::new(SegQueue::new()); + executor::start_multi( + num_threads, + None, + vec![task], + shared_state, + queue.clone(), + &executor::trace_collector, + ); + + let mut paths = Vec::new(); + loop { + match queue.pop() { + Some(Ok((_, mut events))) => { + simplify::hide_initialization(&mut events); + simplify::remove_extra_register_fields(&mut events); + simplify::remove_repeated_register_reads(&mut events); + simplify::remove_unused_register_assumptions(&mut events); + simplify::remove_unused(&mut events); + simplify::propagate_forwards_used_once(&mut events); + simplify::commute_extract(&mut events); + simplify::eval(&mut events); + + let events: Vec> = events.drain(..).rev().collect(); + paths.push(events); + } + + // Error during execution + Some(Err(err)) => { + let msg = format!("{}", err); + eprintln!( + "{}", + err.source_loc().message::( + None, + shared_state.symtab.files(), + &msg, + true, + true + ) + ); + anyhow::bail!("{}", err); + } + // Empty queue + None => break, + } + } + + Ok(paths) +} + +/// Write ISLA trace events to stdout. +fn write_events<'ir, B: BV>( + events: &Vec>, + iarch: &'ir Initialized<'ir, B>, +) -> anyhow::Result<()> { + // Print. + let stdout = std::io::stdout(); + let mut handle = BufWriter::with_capacity(5 * usize::pow(2, 20), stdout.lock()); + let write_opts = WriteOpts::default(); + simplify::write_events_with_opts(&mut handle, &events, &iarch.shared_state, &write_opts) + .unwrap(); + handle.flush().unwrap(); + + Ok(()) +} + +/// Parse Jib IR. +fn parse_ir<'a, 'input, B: BV>( + contents: &'input str, + symtab: &'a mut Symtab<'input>, +) -> anyhow::Result>> { + match ir_parser::IrParser::new().parse(symtab, new_ir_lexer(&contents)) { + Ok(ir) => Ok(ir), + Err(_) => Err(anyhow::Error::msg("bad")), + } +} + +/// Read an entire file into a string. +fn read_to_string>(path: P) -> anyhow::Result { + let mut buffer = String::new(); + let path = path.as_ref(); + if path == Path::new("-") { + let stdin = io::stdin(); + let mut stdin = stdin.lock(); + stdin + .read_to_string(&mut buffer) + .context("failed to read stdin to string")?; + } else { + let mut file = File::open(path)?; + file.read_to_string(&mut buffer) + .with_context(|| format!("failed to read {} to string", path.display()))?; + } + Ok(buffer) +} From a0e811a9aac1786e55bb7a3035e464cfe2025db9 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Mon, 18 Dec 2023 19:18:02 -0500 Subject: [PATCH 14/73] attempting to make x64 work --- Cargo.lock | 1 - cranelift/isle/veri/veri_engine/Cargo.toml | 2 +- cranelift/isle/veri/veri_engine/src/x64.rs | 356 +++++++++++++++++++-- 3 files changed, 335 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 477765983f7c..dd3ff4ea8867 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1790,7 +1790,6 @@ dependencies = [ [[package]] name = "isla-lib" version = "0.2.0" -source = "git+https://github.com/rems-project/isla.git?rev=4134411c0f463807edd788f67b3db34c1899d9b6#4134411c0f463807edd788f67b3db34c1899d9b6" dependencies = [ "ahash 0.7.7", "bincode", diff --git a/cranelift/isle/veri/veri_engine/Cargo.toml b/cranelift/isle/veri/veri_engine/Cargo.toml index 203eb6fcd4cd..2dab78f578d6 100644 --- a/cranelift/isle/veri/veri_engine/Cargo.toml +++ b/cranelift/isle/veri/veri_engine/Cargo.toml @@ -30,7 +30,7 @@ cranelift-isle = { path = "../../isle" } cranelift-codegen = { path = "../../../codegen" } cranelift-reader = { path = "../../../reader" } cranelift-codegen-meta = { path = "../../../codegen/meta" } -isla-lib = { git = "https://github.com/rems-project/isla.git", rev = "4134411c0f463807edd788f67b3db34c1899d9b6" } +isla-lib = { path = "../../../../../isla/isla-lib" } anyhow = { workspace = true } veri_ir = { path = "../veri_ir" } easy-smt = { git = "https://github.com/elliottt/easy-smt.git" } diff --git a/cranelift/isle/veri/veri_engine/src/x64.rs b/cranelift/isle/veri/veri_engine/src/x64.rs index 7f8590efde81..63a70dcfb836 100644 --- a/cranelift/isle/veri/veri_engine/src/x64.rs +++ b/cranelift/isle/veri/veri_engine/src/x64.rs @@ -6,17 +6,23 @@ use cranelift_codegen::isa::x64::{ }; use cranelift_codegen::{settings, MachBuffer, MachInstEmit, Reg, Writable}; use crossbeam::queue::SegQueue; -use isla_lib::bitvector::{b64::B64, BV}; -use isla_lib::config::ISAConfig; -use isla_lib::error::IslaError; -use isla_lib::executor::{self, LocalFrame, TaskState}; +use isla_lib::error::{ExecError, IslaError}; +use isla_lib::executor::{self, freeze_frame, LocalFrame, TaskState}; use isla_lib::init::{initialize_architecture, Initialized}; -use isla_lib::ir::{AssertionMode, Def, IRTypeInfo, Name, Symtab, Val}; +use isla_lib::ir::{AssertionMode, Def, IRTypeInfo, Name, Symtab, Ty, Val}; use isla_lib::ir_lexer::new_ir_lexer; use isla_lib::ir_parser; -use isla_lib::memory::Memory; +use isla_lib::log; +use isla_lib::memory::{Memory, SmtKind}; use isla_lib::simplify::{self, WriteOpts}; -use isla_lib::smt::{self, Checkpoint, Event, Solver}; +use isla_lib::smt::smtlib::{self, bits64}; +use isla_lib::smt::{self, Checkpoint, Event, ReadOpts, Solver, Sym}; +use isla_lib::source_loc::SourceLoc; +use isla_lib::{ + bitvector::{b64::B64, BV}, + zencode, +}; +use isla_lib::{config::ISAConfig, executor::unfreeze_frame}; use sha2::{Digest, Sha256}; use std::fs::File; use std::io::prelude::*; @@ -37,6 +43,7 @@ struct Options { fn main() -> anyhow::Result<()> { let options = Options::parse(); + log::set_flags(log::VERBOSE | log::MEMORY); // Parse ISLA Architecture. let contents = read_to_string(&options.arch)?; @@ -105,31 +112,322 @@ fn assemble(inst: &Inst) -> Vec { return buffer.data().to_vec(); } +#[derive(Debug, Clone)] +struct SeqMemory { + memory_var: Sym, +} + +impl isla_lib::memory::MemoryCallbacks for SeqMemory { + fn symbolic_read( + &self, + regions: &[isla_lib::memory::Region], + solver: &mut Solver, + value: &Val, + _read_kind: &Val, + address: &Val, + bytes: u32, + _tag: &Option>, + opts: &ReadOpts, + ) { + use isla_lib::smt::smtlib::{Def, Exp}; + + let read_exp = smt_value(value) + .unwrap_or_else(|err| panic!("Bad memory read value {:?}: {}", value, err)); + let addr_exp = smt_value(address) + .unwrap_or_else(|err| panic!("Bad read address value {:?}: {}", address, err)); + let read_prop = Exp::Eq( + Box::new(read_exp.clone()), + Box::new(smt_read_exp(self.memory_var, &addr_exp, bytes as u64)), + ); + let kind = if opts.is_ifetch { + SmtKind::ReadInstr + } else if opts.is_exclusive { + // We produce a dummy read so that failed store exclusives still get address + // constraints, but the memory must be writable. + SmtKind::WriteData + } else { + SmtKind::ReadData + }; + let address_constraint = + isla_lib::memory::smt_address_constraint(regions, &addr_exp, bytes, kind, solver, None); + + let full_constraint = Exp::And(Box::new(address_constraint), Box::new(read_prop)); + + solver.add(Def::Assert(full_constraint)); + } + + fn symbolic_write( + &mut self, + regions: &[isla_lib::memory::Region], + solver: &mut Solver, + _value: Sym, + _read_kind: &Val, + address: &Val, + data: &Val, + bytes: u32, + _tag: &Option>, + _opts: &smt::WriteOpts, + ) { + use isla_lib::smt::smtlib::{Def, Exp}; + + let data_exp = smt_value(data) + .unwrap_or_else(|err| panic!("Bad memory write value {:?}: {}", data, err)); + let addr_exp = smt_value(address) + .unwrap_or_else(|err| panic!("Bad write address value {:?}: {}", address, err)); + // TODO: endianness? + let mut mem_exp = Exp::Store( + Box::new(Exp::Var(self.memory_var)), + Box::new(addr_exp.clone()), + Box::new(Exp::Extract(7, 0, Box::new(data_exp.clone()))), + ); + for i in 1..bytes { + mem_exp = Exp::Store( + Box::new(mem_exp), + Box::new(Exp::Bvadd( + Box::new(addr_exp.clone()), + Box::new(bits64(i as u64, 64)), + )), + Box::new(Exp::Extract(i * 8 + 7, i * 8, Box::new(data_exp.clone()))), + ) + } + self.memory_var = solver.fresh(); + solver.add(Def::DefineConst(self.memory_var, mem_exp)); + + let kind = SmtKind::WriteData; + let address_constraint = + isla_lib::memory::smt_address_constraint(regions, &addr_exp, bytes, kind, solver, None); + solver.add(Def::Assert(address_constraint)); + } + + fn symbolic_write_tag( + &mut self, + regions: &[isla_lib::memory::Region], + solver: &mut Solver, + _value: Sym, + _write_kind: &Val, + address: &Val, + _tag: &Val, + ) { + use isla_lib::smt::smtlib::Def; + + let addr_exp = smt_value(address) + .unwrap_or_else(|err| panic!("Bad write address value {:?}: {}", address, err)); + + let kind = SmtKind::WriteData; + // Only insist on the start address being in range, leave the size and alignment to the + // model + let address_constraint = + isla_lib::memory::smt_address_constraint(regions, &addr_exp, 1, kind, solver, None); + solver.add(Def::Assert(address_constraint)); + } +} + +fn smt_read_exp(memory: Sym, addr_exp: &smtlib::Exp, bytes: u64) -> smtlib::Exp { + use smtlib::Exp; + // TODO: endianness? + let mut mem_exp = Exp::Select(Box::new(Exp::Var(memory)), Box::new(addr_exp.clone())); + for i in 1..bytes { + mem_exp = Exp::Concat( + Box::new(Exp::Select( + Box::new(Exp::Var(memory)), + Box::new(Exp::Bvadd( + Box::new(addr_exp.clone()), + Box::new(bits64(i as u64, 64)), + )), + )), + Box::new(mem_exp), + ) + } + mem_exp +} + fn trace_opcode<'ir, B: BV>( - machine_code: &Vec, + opcode: &Vec, iarch: &'ir Initialized<'ir, B>, ) -> anyhow::Result>>> { let shared_state = &&iarch.shared_state; + let symtab = &shared_state.symtab; let initial_checkpoint = Checkpoint::new(); let solver_cfg = smt::Config::new(); let solver_ctx = smt::Context::new(solver_cfg); let mut solver = Solver::from_checkpoint(&solver_ctx, initial_checkpoint); - let checkpoint = smt::checkpoint(&mut solver); + let memory = Memory::new(); - let opcode_val = Val::Bits(B::from_bytes(&machine_code)); + // Initialization ----------------------------------------------------------- + // - run initialization function to set processor in 64-bit mode - let footprint_function = "zisla_footprint"; - let function_id = shared_state.symtab.lookup(&footprint_function); + let init_function = zencode::encode("initialise_64_bit_mode"); + let function_id = shared_state.symtab.lookup(&init_function); let (args, ret_ty, instrs) = shared_state.functions.get(&function_id).unwrap(); - let memory = Memory::new(); + let task_state = TaskState::::new(); - let task = LocalFrame::new(function_id, args, ret_ty, Some(&[opcode_val]), instrs) + let checkpoint = smt::checkpoint(&mut solver); + let task = LocalFrame::new(function_id, args, ret_ty, None, instrs) .add_lets(&iarch.lets) .add_regs(&iarch.regs) .set_memory(memory) .task_with_checkpoint(0, &task_state, checkpoint); + let queue = Arc::new(SegQueue::new()); + executor::start_single( + task, + &shared_state, + &queue, + &move |_tid, _task_id, result, _shared_state, mut solver, queue| match result { + Ok((_, frame)) => { + queue.push((freeze_frame(&frame), smt::checkpoint(&mut solver))); + } + Err(err) => panic!("Initialisation failed: {:?}", err), + }, + ); + assert_eq!(queue.len(), 1); + let (frame, checkpoint) = queue.pop().expect("pop failed"); + + // Initialize registers ----------------------------------------------------- + // - set symbolic values for all general-purpose registers + + let mut local_frame = executor::unfreeze_frame(&frame); + for (n, ty) in &shared_state.registers { + let name = zencode::decode(symtab.to_str(*n)); + println!("register: {} {:?}", name, ty); + + // Only handle general-purpose registers. + if let Ty::Bits(bits) = ty { + let var = solver.fresh(); + solver.add(smtlib::Def::DeclareConst(var, smtlib::Ty::BitVec(*bits))); + let val = Val::Symbolic(var); + local_frame.regs_mut().assign(*n, val, shared_state); + } + } + + let frame = freeze_frame(&local_frame); + + // Setup code region -------------------------------------------------------- + + let mut local_frame = unfreeze_frame(&frame); + + let init_pc = 0x401000; + local_frame + .memory_mut() + .add_symbolic_code_region(init_pc..init_pc + 0x10000); + + let frame = freeze_frame(&local_frame); + + // Set initial program counter ---------------------------------------------- + + let mut local_frame = unfreeze_frame(&frame); + + // let (pc_str, pc_acc) = target.pc_reg(); + // let pc_id = shared_state.symtab.lookup(&pc_str); + let pc_name = zencode::encode("rip"); + let pc_id = symtab.lookup(&pc_name); + let pc = local_frame + .regs() + .get_last_if_initialized(pc_id) + .unwrap() + .clone(); + + // let pc_type = register_types.get(&pc_id).unwrap(); + // let pc_addr = apply_accessor_val_mut(shared_state, &mut pc_full, &pc_acc); + // let pc_type = apply_accessor_type(shared_state, &pc_type, &pc_acc); + // match pc_type { + // Ty::Bits(n) => { + // use smtlib::{Def, Exp}; + solver.add(smtlib::Def::Assert(smtlib::Exp::Eq( + Box::new(smt_value(&pc).unwrap()), + Box::new(smtlib::Exp::Bits64(B64::new(init_pc, 64))), + ))); + // } + // _ => panic!("Bad type for PC: {:?}", pc_type), + // }; + local_frame.regs_mut().assign(pc_id, pc, shared_state); + + let frame = freeze_frame(&local_frame); + + // Setup memory ------------------------------------------------------------- + // TODO + + let mut local_frame = unfreeze_frame(&frame); + + let memory_var = solver.fresh(); + solver.add(smtlib::Def::DeclareConst( + memory_var, + smtlib::Ty::Array( + Box::new(smtlib::Ty::BitVec(64)), + Box::new(smtlib::Ty::BitVec(8)), + ), + )); + + let memory_info: Box> = + Box::new(SeqMemory { memory_var }); + local_frame.memory_mut().set_client_info(memory_info); + local_frame.memory().log(); + + // executor::reset_registers(0, &mut local_frame, &executor::TaskState::new(), shared_state, &mut solver, SourceLoc::unknown()).unwrap_or_else(|e| panic!("Unable to apply reset-time registers: {}", e)); + + // (freeze_frame(&local_frame), smt::checkpoint(&mut solver), reg_vars) + let frame = freeze_frame(&local_frame); + + // Setup opcode ------------------------------------------------------------- + + let local_frame = unfreeze_frame(&frame); + + const OPCODE_LEN: usize = 16; + assert!(opcode.len() <= OPCODE_LEN); + let mut opcode = opcode.clone(); + opcode.resize(OPCODE_LEN, 0x90); + + let opcode_num_bytes = opcode.len(); + let opcode_num_bits = opcode_num_bytes * 8; + + // Read the program counter address from memory. + let pc = local_frame.regs().get_last_if_initialized(pc_id).unwrap(); + let read_val = local_frame + .memory() + .read( + Val::Unit, + pc.clone(), + Val::I128(opcode_num_bytes as i128), + &mut solver, + false, + ReadOpts::ifetch(), + ) + .unwrap(); + + // Setup a variable equal to the opcode. + let opcode_var = solver.fresh(); + solver.add(smtlib::Def::DeclareConst( + opcode_var, + smtlib::Ty::BitVec(opcode_num_bits as u32), + )); + solver.add(smtlib::Def::Assert(smtlib::Exp::Eq( + Box::new(smtlib::Exp::Var(opcode_var)), + Box::new(smt_bytes(&opcode)), + ))); + + // Assert the program counter read equals the opcode. + let read_exp = smt_value(&read_val).unwrap(); + solver.add(smtlib::Def::Assert(smtlib::Exp::Eq( + Box::new(smtlib::Exp::Var(opcode_var)), + Box::new(read_exp), + ))); + + let frame = freeze_frame(&local_frame); + + // Execute fetch and decode ------------------------------------------------- + + let local_frame = unfreeze_frame(&frame); + + let run_instruction_function = zencode::encode("x86_fetch_decode_execute"); + let function_id = shared_state.symtab.lookup(&run_instruction_function); + let (args, ret_ty, instrs) = shared_state.functions.get(&function_id).unwrap(); + + let task_state = TaskState::::new(); + let task = local_frame + .new_call(function_id, args, ret_ty, None, instrs) + .task_with_checkpoint(1, &task_state, checkpoint); + let num_threads = 1; let queue = Arc::new(SegQueue::new()); executor::start_multi( @@ -145,14 +443,14 @@ fn trace_opcode<'ir, B: BV>( loop { match queue.pop() { Some(Ok((_, mut events))) => { - simplify::hide_initialization(&mut events); - simplify::remove_extra_register_fields(&mut events); - simplify::remove_repeated_register_reads(&mut events); - simplify::remove_unused_register_assumptions(&mut events); - simplify::remove_unused(&mut events); - simplify::propagate_forwards_used_once(&mut events); - simplify::commute_extract(&mut events); - simplify::eval(&mut events); + //simplify::hide_initialization(&mut events); + //simplify::remove_extra_register_fields(&mut events); + //simplify::remove_repeated_register_reads(&mut events); + //simplify::remove_unused_register_assumptions(&mut events); + //simplify::remove_unused(&mut events); + //simplify::propagate_forwards_used_once(&mut events); + //simplify::commute_extract(&mut events); + //simplify::eval(&mut events); let events: Vec> = events.drain(..).rev().collect(); paths.push(events); @@ -181,6 +479,20 @@ fn trace_opcode<'ir, B: BV>( Ok(paths) } +fn smt_value(v: &Val) -> Result, ExecError> { + isla_lib::primop_util::smt_value(v, SourceLoc::unknown()) +} + +fn smt_bytes(bytes: &Vec) -> smtlib::Exp { + let mut bits = Vec::with_capacity(bytes.len() * 8); + for byte in bytes { + for i in 0..8 { + bits.push((byte >> i) & 1 == 1); + } + } + smtlib::Exp::Bits(bits) +} + /// Write ISLA trace events to stdout. fn write_events<'ir, B: BV>( events: &Vec>, From 63d64e32d4b63c06e87ca2a3d662fa7529caf9ea Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Sun, 24 Dec 2023 05:34:49 -0500 Subject: [PATCH 15/73] first working trace output for x86 --- cranelift/isle/veri/veri_engine/src/x64.rs | 401 ++++++++++----------- 1 file changed, 199 insertions(+), 202 deletions(-) diff --git a/cranelift/isle/veri/veri_engine/src/x64.rs b/cranelift/isle/veri/veri_engine/src/x64.rs index 63a70dcfb836..1049c6000aa7 100644 --- a/cranelift/isle/veri/veri_engine/src/x64.rs +++ b/cranelift/isle/veri/veri_engine/src/x64.rs @@ -5,8 +5,8 @@ use cranelift_codegen::isa::x64::{ inst::{args::*, *}, }; use cranelift_codegen::{settings, MachBuffer, MachInstEmit, Reg, Writable}; +use cranelift_isle::overlap::check; use crossbeam::queue::SegQueue; -use isla_lib::error::{ExecError, IslaError}; use isla_lib::executor::{self, freeze_frame, LocalFrame, TaskState}; use isla_lib::init::{initialize_architecture, Initialized}; use isla_lib::ir::{AssertionMode, Def, IRTypeInfo, Name, Symtab, Ty, Val}; @@ -23,12 +23,16 @@ use isla_lib::{ zencode, }; use isla_lib::{config::ISAConfig, executor::unfreeze_frame}; +use isla_lib::{ + error::{ExecError, IslaError}, + memory::Address, +}; use sha2::{Digest, Sha256}; -use std::fs::File; use std::io::prelude::*; use std::io::{self, BufWriter, Read}; use std::path::{Path, PathBuf}; use std::sync::Arc; +use std::{collections::HashMap, fs::File}; #[derive(Parser)] struct Options { @@ -93,10 +97,12 @@ fn main() -> anyhow::Result<()> { let paths = trace_opcode(&machine_code, &iarch)?; // Dump. - for events in paths { + for events in &paths { write_events(&events, &iarch)?; } + println!("generated {} trace paths", paths.len()); + Ok(()) } @@ -112,135 +118,6 @@ fn assemble(inst: &Inst) -> Vec { return buffer.data().to_vec(); } -#[derive(Debug, Clone)] -struct SeqMemory { - memory_var: Sym, -} - -impl isla_lib::memory::MemoryCallbacks for SeqMemory { - fn symbolic_read( - &self, - regions: &[isla_lib::memory::Region], - solver: &mut Solver, - value: &Val, - _read_kind: &Val, - address: &Val, - bytes: u32, - _tag: &Option>, - opts: &ReadOpts, - ) { - use isla_lib::smt::smtlib::{Def, Exp}; - - let read_exp = smt_value(value) - .unwrap_or_else(|err| panic!("Bad memory read value {:?}: {}", value, err)); - let addr_exp = smt_value(address) - .unwrap_or_else(|err| panic!("Bad read address value {:?}: {}", address, err)); - let read_prop = Exp::Eq( - Box::new(read_exp.clone()), - Box::new(smt_read_exp(self.memory_var, &addr_exp, bytes as u64)), - ); - let kind = if opts.is_ifetch { - SmtKind::ReadInstr - } else if opts.is_exclusive { - // We produce a dummy read so that failed store exclusives still get address - // constraints, but the memory must be writable. - SmtKind::WriteData - } else { - SmtKind::ReadData - }; - let address_constraint = - isla_lib::memory::smt_address_constraint(regions, &addr_exp, bytes, kind, solver, None); - - let full_constraint = Exp::And(Box::new(address_constraint), Box::new(read_prop)); - - solver.add(Def::Assert(full_constraint)); - } - - fn symbolic_write( - &mut self, - regions: &[isla_lib::memory::Region], - solver: &mut Solver, - _value: Sym, - _read_kind: &Val, - address: &Val, - data: &Val, - bytes: u32, - _tag: &Option>, - _opts: &smt::WriteOpts, - ) { - use isla_lib::smt::smtlib::{Def, Exp}; - - let data_exp = smt_value(data) - .unwrap_or_else(|err| panic!("Bad memory write value {:?}: {}", data, err)); - let addr_exp = smt_value(address) - .unwrap_or_else(|err| panic!("Bad write address value {:?}: {}", address, err)); - // TODO: endianness? - let mut mem_exp = Exp::Store( - Box::new(Exp::Var(self.memory_var)), - Box::new(addr_exp.clone()), - Box::new(Exp::Extract(7, 0, Box::new(data_exp.clone()))), - ); - for i in 1..bytes { - mem_exp = Exp::Store( - Box::new(mem_exp), - Box::new(Exp::Bvadd( - Box::new(addr_exp.clone()), - Box::new(bits64(i as u64, 64)), - )), - Box::new(Exp::Extract(i * 8 + 7, i * 8, Box::new(data_exp.clone()))), - ) - } - self.memory_var = solver.fresh(); - solver.add(Def::DefineConst(self.memory_var, mem_exp)); - - let kind = SmtKind::WriteData; - let address_constraint = - isla_lib::memory::smt_address_constraint(regions, &addr_exp, bytes, kind, solver, None); - solver.add(Def::Assert(address_constraint)); - } - - fn symbolic_write_tag( - &mut self, - regions: &[isla_lib::memory::Region], - solver: &mut Solver, - _value: Sym, - _write_kind: &Val, - address: &Val, - _tag: &Val, - ) { - use isla_lib::smt::smtlib::Def; - - let addr_exp = smt_value(address) - .unwrap_or_else(|err| panic!("Bad write address value {:?}: {}", address, err)); - - let kind = SmtKind::WriteData; - // Only insist on the start address being in range, leave the size and alignment to the - // model - let address_constraint = - isla_lib::memory::smt_address_constraint(regions, &addr_exp, 1, kind, solver, None); - solver.add(Def::Assert(address_constraint)); - } -} - -fn smt_read_exp(memory: Sym, addr_exp: &smtlib::Exp, bytes: u64) -> smtlib::Exp { - use smtlib::Exp; - // TODO: endianness? - let mut mem_exp = Exp::Select(Box::new(Exp::Var(memory)), Box::new(addr_exp.clone())); - for i in 1..bytes { - mem_exp = Exp::Concat( - Box::new(Exp::Select( - Box::new(Exp::Var(memory)), - Box::new(Exp::Bvadd( - Box::new(addr_exp.clone()), - Box::new(bits64(i as u64, 64)), - )), - )), - Box::new(mem_exp), - ) - } - mem_exp -} - fn trace_opcode<'ir, B: BV>( opcode: &Vec, iarch: &'ir Initialized<'ir, B>, @@ -284,6 +161,9 @@ fn trace_opcode<'ir, B: BV>( assert_eq!(queue.len(), 1); let (frame, checkpoint) = queue.pop().expect("pop failed"); + dump_checkpoint(&checkpoint, iarch)?; + let mut solver = Solver::from_checkpoint(&solver_ctx, checkpoint); + // Initialize registers ----------------------------------------------------- // - set symbolic values for all general-purpose registers @@ -303,52 +183,14 @@ fn trace_opcode<'ir, B: BV>( let frame = freeze_frame(&local_frame); - // Setup code region -------------------------------------------------------- + // Setup memory ------------------------------------------------------------- let mut local_frame = unfreeze_frame(&frame); - let init_pc = 0x401000; + const INIT_PC: Address = 0x401000; local_frame .memory_mut() - .add_symbolic_code_region(init_pc..init_pc + 0x10000); - - let frame = freeze_frame(&local_frame); - - // Set initial program counter ---------------------------------------------- - - let mut local_frame = unfreeze_frame(&frame); - - // let (pc_str, pc_acc) = target.pc_reg(); - // let pc_id = shared_state.symtab.lookup(&pc_str); - let pc_name = zencode::encode("rip"); - let pc_id = symtab.lookup(&pc_name); - let pc = local_frame - .regs() - .get_last_if_initialized(pc_id) - .unwrap() - .clone(); - - // let pc_type = register_types.get(&pc_id).unwrap(); - // let pc_addr = apply_accessor_val_mut(shared_state, &mut pc_full, &pc_acc); - // let pc_type = apply_accessor_type(shared_state, &pc_type, &pc_acc); - // match pc_type { - // Ty::Bits(n) => { - // use smtlib::{Def, Exp}; - solver.add(smtlib::Def::Assert(smtlib::Exp::Eq( - Box::new(smt_value(&pc).unwrap()), - Box::new(smtlib::Exp::Bits64(B64::new(init_pc, 64))), - ))); - // } - // _ => panic!("Bad type for PC: {:?}", pc_type), - // }; - local_frame.regs_mut().assign(pc_id, pc, shared_state); - - let frame = freeze_frame(&local_frame); - - // Setup memory ------------------------------------------------------------- - // TODO - - let mut local_frame = unfreeze_frame(&frame); + .add_symbolic_code_region(INIT_PC..INIT_PC + 0x10000); let memory_var = solver.fresh(); solver.add(smtlib::Def::DeclareConst( @@ -359,54 +201,73 @@ fn trace_opcode<'ir, B: BV>( ), )); - let memory_info: Box> = + let memory_client_info: Box> = Box::new(SeqMemory { memory_var }); - local_frame.memory_mut().set_client_info(memory_info); - local_frame.memory().log(); - - // executor::reset_registers(0, &mut local_frame, &executor::TaskState::new(), shared_state, &mut solver, SourceLoc::unknown()).unwrap_or_else(|e| panic!("Unable to apply reset-time registers: {}", e)); + local_frame.memory_mut().set_client_info(memory_client_info); - // (freeze_frame(&local_frame), smt::checkpoint(&mut solver), reg_vars) let frame = freeze_frame(&local_frame); - // Setup opcode ------------------------------------------------------------- + // // Write opcode ------------------------------------------------------------- - let local_frame = unfreeze_frame(&frame); + // let mut local_frame = unfreeze_frame(&frame); - const OPCODE_LEN: usize = 16; - assert!(opcode.len() <= OPCODE_LEN); - let mut opcode = opcode.clone(); - opcode.resize(OPCODE_LEN, 0x90); + // for (i, opcode_byte) in opcode.iter().enumerate() { + // local_frame + // .memory_mut() + // .write( + // Val::Unit, + // Val::Bits(B::from_u64(INIT_PC + i as u64)), + // Val::Bits(B::from_u8(opcode_byte.clone())), + // &mut solver, + // None, + // smt::WriteOpts::default(), + // ) + // .expect("memory write failed"); + // } - let opcode_num_bytes = opcode.len(); - let opcode_num_bits = opcode_num_bytes * 8; + // let frame = freeze_frame(&local_frame); - // Read the program counter address from memory. + // Set initial program counter ---------------------------------------------- + + let local_frame = unfreeze_frame(&frame); + + let pc_name = zencode::encode("rip"); + let pc_id = symtab.lookup(&pc_name); let pc = local_frame.regs().get_last_if_initialized(pc_id).unwrap(); + + solver.add(smtlib::Def::Assert(smtlib::Exp::Eq( + Box::new(smt_value(pc).unwrap()), + Box::new(smtlib::Exp::Bits64(B64::from_u64(INIT_PC))), + ))); + + let frame = freeze_frame(&local_frame); + + // Setup opcode ------------------------------------------------------------- + + let local_frame = unfreeze_frame(&frame); + let read_val = local_frame .memory() .read( - Val::Unit, + Val::Unit, /* read_kind */ pc.clone(), - Val::I128(opcode_num_bytes as i128), + Val::I128(opcode.len() as i128), &mut solver, false, ReadOpts::ifetch(), ) .unwrap(); - // Setup a variable equal to the opcode. let opcode_var = solver.fresh(); solver.add(smtlib::Def::DeclareConst( opcode_var, - smtlib::Ty::BitVec(opcode_num_bits as u32), + smtlib::Ty::BitVec(8 * opcode.len() as u32), )); solver.add(smtlib::Def::Assert(smtlib::Exp::Eq( Box::new(smtlib::Exp::Var(opcode_var)), - Box::new(smt_bytes(&opcode)), + Box::new(smt_bytes(opcode)), ))); - // Assert the program counter read equals the opcode. let read_exp = smt_value(&read_val).unwrap(); solver.add(smtlib::Def::Assert(smtlib::Exp::Eq( Box::new(smtlib::Exp::Var(opcode_var)), @@ -415,10 +276,18 @@ fn trace_opcode<'ir, B: BV>( let frame = freeze_frame(&local_frame); + // Debug dump --------------------------------------------------------------- + + assert_eq!(solver.check_sat(), smt::SmtResult::Sat); + let checkpoint = smt::checkpoint(&mut solver); + dump_checkpoint(&checkpoint, iarch)?; + // Execute fetch and decode ------------------------------------------------- let local_frame = unfreeze_frame(&frame); + local_frame.memory().log(); + let run_instruction_function = zencode::encode("x86_fetch_decode_execute"); let function_id = shared_state.symtab.lookup(&run_instruction_function); let (args, ret_ty, instrs) = shared_state.functions.get(&function_id).unwrap(); @@ -443,14 +312,14 @@ fn trace_opcode<'ir, B: BV>( loop { match queue.pop() { Some(Ok((_, mut events))) => { - //simplify::hide_initialization(&mut events); - //simplify::remove_extra_register_fields(&mut events); - //simplify::remove_repeated_register_reads(&mut events); - //simplify::remove_unused_register_assumptions(&mut events); - //simplify::remove_unused(&mut events); - //simplify::propagate_forwards_used_once(&mut events); - //simplify::commute_extract(&mut events); - //simplify::eval(&mut events); + simplify::hide_initialization(&mut events); + simplify::remove_extra_register_fields(&mut events); + simplify::remove_repeated_register_reads(&mut events); + simplify::remove_unused_register_assumptions(&mut events); + simplify::remove_unused(&mut events); + simplify::propagate_forwards_used_once(&mut events); + simplify::commute_extract(&mut events); + simplify::eval(&mut events); let events: Vec> = events.drain(..).rev().collect(); paths.push(events); @@ -479,10 +348,127 @@ fn trace_opcode<'ir, B: BV>( Ok(paths) } +#[derive(Debug, Clone)] +struct SeqMemory { + memory_var: Sym, +} + +impl isla_lib::memory::MemoryCallbacks for SeqMemory { + fn symbolic_read( + &self, + regions: &[isla_lib::memory::Region], + solver: &mut Solver, + value: &Val, + _read_kind: &Val, + address: &Val, + bytes: u32, + _tag: &Option>, + opts: &ReadOpts, + ) { + use isla_lib::smt::smtlib::{Def, Exp}; + + let read_exp = smt_value(value) + .unwrap_or_else(|err| panic!("Bad memory read value {:?}: {}", value, err)); + let addr_exp = smt_value(address) + .unwrap_or_else(|err| panic!("Bad read address value {:?}: {}", address, err)); + let read_prop = Exp::Eq( + Box::new(read_exp.clone()), + Box::new(smt_read_exp(self.memory_var, &addr_exp, bytes as u64)), + ); + let kind = if opts.is_ifetch { + SmtKind::ReadInstr + } else if opts.is_exclusive { + // We produce a dummy read so that failed store exclusives still get address + // constraints, but the memory must be writable. + SmtKind::WriteData + } else { + SmtKind::ReadData + }; + let address_constraint = + isla_lib::memory::smt_address_constraint(regions, &addr_exp, bytes, kind, solver, None); + + let full_constraint = Exp::And(Box::new(address_constraint), Box::new(read_prop)); + + solver.add(Def::Assert(full_constraint)); + } + + fn symbolic_write( + &mut self, + regions: &[isla_lib::memory::Region], + solver: &mut Solver, + _value: Sym, + _read_kind: &Val, + address: &Val, + data: &Val, + bytes: u32, + _tag: &Option>, + _opts: &smt::WriteOpts, + ) { + use isla_lib::smt::smtlib::{Def, Exp}; + + let data_exp = smt_value(data) + .unwrap_or_else(|err| panic!("Bad memory write value {:?}: {}", data, err)); + let addr_exp = smt_value(address) + .unwrap_or_else(|err| panic!("Bad write address value {:?}: {}", address, err)); + // TODO: endianness? + let mut mem_exp = Exp::Store( + Box::new(Exp::Var(self.memory_var)), + Box::new(addr_exp.clone()), + Box::new(Exp::Extract(7, 0, Box::new(data_exp.clone()))), + ); + for i in 1..bytes { + mem_exp = Exp::Store( + Box::new(mem_exp), + Box::new(Exp::Bvadd( + Box::new(addr_exp.clone()), + Box::new(bits64(i as u64, 64)), + )), + Box::new(Exp::Extract(i * 8 + 7, i * 8, Box::new(data_exp.clone()))), + ) + } + self.memory_var = solver.fresh(); + solver.add(Def::DefineConst(self.memory_var, mem_exp)); + let kind = SmtKind::WriteData; + let address_constraint = + isla_lib::memory::smt_address_constraint(regions, &addr_exp, bytes, kind, solver, None); + solver.add(Def::Assert(address_constraint)); + } + + fn symbolic_write_tag( + &mut self, + _regions: &[isla_lib::memory::Region], + _solver: &mut Solver, + _value: Sym, + _write_kind: &Val, + _address: &Val, + _tag: &Val, + ) { + } +} + fn smt_value(v: &Val) -> Result, ExecError> { isla_lib::primop_util::smt_value(v, SourceLoc::unknown()) } +fn smt_read_exp(memory: Sym, addr_exp: &smtlib::Exp, bytes: u64) -> smtlib::Exp { + use smtlib::Exp; + // TODO: endianness? + let mut mem_exp = Exp::Select(Box::new(Exp::Var(memory)), Box::new(addr_exp.clone())); + for i in 1..bytes { + mem_exp = Exp::Concat( + Box::new(Exp::Select( + Box::new(Exp::Var(memory)), + Box::new(Exp::Bvadd( + Box::new(addr_exp.clone()), + Box::new(bits64(i as u64, 64)), + )), + )), + Box::new(mem_exp), + ) + } + mem_exp +} + fn smt_bytes(bytes: &Vec) -> smtlib::Exp { let mut bits = Vec::with_capacity(bytes.len() * 8); for byte in bytes { @@ -493,6 +479,17 @@ fn smt_bytes(bytes: &Vec) -> smtlib::Exp { smtlib::Exp::Bits(bits) } +fn dump_checkpoint<'ir, B: BV>( + checkpoint: &Checkpoint, + iarch: &'ir Initialized<'ir, B>, +) -> anyhow::Result<()> { + if let Some(trace) = checkpoint.trace() { + let events: Vec> = trace.to_vec().into_iter().cloned().collect(); + write_events(&events, iarch)?; + } + Ok(()) +} + /// Write ISLA trace events to stdout. fn write_events<'ir, B: BV>( events: &Vec>, From 9358c6b3b721ac3cee5c099affbb33eaf617a876 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Sun, 24 Dec 2023 06:32:44 -0500 Subject: [PATCH 16/73] write x64 traces to files --- cranelift/isle/veri/veri_engine/src/x64.rs | 86 ++++++++-------------- 1 file changed, 30 insertions(+), 56 deletions(-) diff --git a/cranelift/isle/veri/veri_engine/src/x64.rs b/cranelift/isle/veri/veri_engine/src/x64.rs index 1049c6000aa7..fed288dc5472 100644 --- a/cranelift/isle/veri/veri_engine/src/x64.rs +++ b/cranelift/isle/veri/veri_engine/src/x64.rs @@ -1,11 +1,9 @@ -use anyhow::Context as _; use clap::Parser; use cranelift_codegen::isa::x64::{ self, inst::{args::*, *}, }; use cranelift_codegen::{settings, MachBuffer, MachInstEmit, Reg, Writable}; -use cranelift_isle::overlap::check; use crossbeam::queue::SegQueue; use isla_lib::executor::{self, freeze_frame, LocalFrame, TaskState}; use isla_lib::init::{initialize_architecture, Initialized}; @@ -29,10 +27,9 @@ use isla_lib::{ }; use sha2::{Digest, Sha256}; use std::io::prelude::*; -use std::io::{self, BufWriter, Read}; -use std::path::{Path, PathBuf}; +use std::io::BufWriter; +use std::path::PathBuf; use std::sync::Arc; -use std::{collections::HashMap, fs::File}; #[derive(Parser)] struct Options { @@ -43,14 +40,18 @@ struct Options { /// ISA config file. #[clap(long)] isa_config: PathBuf, + + /// Trace output directory. + #[clap(long, default_value = ".")] + output_dir: PathBuf, } fn main() -> anyhow::Result<()> { let options = Options::parse(); - log::set_flags(log::VERBOSE | log::MEMORY); + log::set_flags(log::VERBOSE); // Parse ISLA Architecture. - let contents = read_to_string(&options.arch)?; + let contents = std::fs::read_to_string(&options.arch)?; let mut symtab = Symtab::new(); let mut arch = parse_ir::(&contents, &mut symtab)?; @@ -97,11 +98,19 @@ fn main() -> anyhow::Result<()> { let paths = trace_opcode(&machine_code, &iarch)?; // Dump. - for events in &paths { - write_events(&events, &iarch)?; + for (i, events) in paths.iter().enumerate() { + let filename = format!("trace{i:04}.out"); + let path = options.output_dir.join(filename); + log!(log::VERBOSE, format!("write trace to {}", path.display())); + + let file = std::fs::File::create(path)?; + write_events(&events, &iarch, file)?; } - println!("generated {} trace paths", paths.len()); + log!( + log::VERBOSE, + format!("generated {} trace paths", paths.len()) + ); Ok(()) } @@ -161,7 +170,6 @@ fn trace_opcode<'ir, B: BV>( assert_eq!(queue.len(), 1); let (frame, checkpoint) = queue.pop().expect("pop failed"); - dump_checkpoint(&checkpoint, iarch)?; let mut solver = Solver::from_checkpoint(&solver_ctx, checkpoint); // Initialize registers ----------------------------------------------------- @@ -169,9 +177,6 @@ fn trace_opcode<'ir, B: BV>( let mut local_frame = executor::unfreeze_frame(&frame); for (n, ty) in &shared_state.registers { - let name = zencode::decode(symtab.to_str(*n)); - println!("register: {} {:?}", name, ty); - // Only handle general-purpose registers. if let Ty::Bits(bits) = ty { let var = solver.fresh(); @@ -207,26 +212,6 @@ fn trace_opcode<'ir, B: BV>( let frame = freeze_frame(&local_frame); - // // Write opcode ------------------------------------------------------------- - - // let mut local_frame = unfreeze_frame(&frame); - - // for (i, opcode_byte) in opcode.iter().enumerate() { - // local_frame - // .memory_mut() - // .write( - // Val::Unit, - // Val::Bits(B::from_u64(INIT_PC + i as u64)), - // Val::Bits(B::from_u8(opcode_byte.clone())), - // &mut solver, - // None, - // smt::WriteOpts::default(), - // ) - // .expect("memory write failed"); - // } - - // let frame = freeze_frame(&local_frame); - // Set initial program counter ---------------------------------------------- let local_frame = unfreeze_frame(&frame); @@ -485,19 +470,26 @@ fn dump_checkpoint<'ir, B: BV>( ) -> anyhow::Result<()> { if let Some(trace) = checkpoint.trace() { let events: Vec> = trace.to_vec().into_iter().cloned().collect(); - write_events(&events, iarch)?; + write_events_to_stdout(&events, iarch)?; } Ok(()) } /// Write ISLA trace events to stdout. +fn write_events_to_stdout<'ir, B: BV>( + events: &Vec>, + iarch: &'ir Initialized<'ir, B>, +) -> anyhow::Result<()> { + let stdout = std::io::stdout().lock(); + write_events(events, iarch, stdout) +} + fn write_events<'ir, B: BV>( events: &Vec>, iarch: &'ir Initialized<'ir, B>, + w: impl Sized + Write, ) -> anyhow::Result<()> { - // Print. - let stdout = std::io::stdout(); - let mut handle = BufWriter::with_capacity(5 * usize::pow(2, 20), stdout.lock()); + let mut handle = BufWriter::with_capacity(5 * usize::pow(2, 20), w); let write_opts = WriteOpts::default(); simplify::write_events_with_opts(&mut handle, &events, &iarch.shared_state, &write_opts) .unwrap(); @@ -516,21 +508,3 @@ fn parse_ir<'a, 'input, B: BV>( Err(_) => Err(anyhow::Error::msg("bad")), } } - -/// Read an entire file into a string. -fn read_to_string>(path: P) -> anyhow::Result { - let mut buffer = String::new(); - let path = path.as_ref(); - if path == Path::new("-") { - let stdin = io::stdin(); - let mut stdin = stdin.lock(); - stdin - .read_to_string(&mut buffer) - .context("failed to read stdin to string")?; - } else { - let mut file = File::open(path)?; - file.read_to_string(&mut buffer) - .with_context(|| format!("failed to read {} to string", path.display()))?; - } - Ok(buffer) -} From 2b24eb5e75f0e682ff0a587b3daeb1567409a544 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Sun, 24 Dec 2023 13:41:04 -0500 Subject: [PATCH 17/73] linearization --- cranelift/isle/veri/veri_engine/src/x64.rs | 65 +++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/cranelift/isle/veri/veri_engine/src/x64.rs b/cranelift/isle/veri/veri_engine/src/x64.rs index fed288dc5472..f680bbf71ad5 100644 --- a/cranelift/isle/veri/veri_engine/src/x64.rs +++ b/cranelift/isle/veri/veri_engine/src/x64.rs @@ -5,7 +5,6 @@ use cranelift_codegen::isa::x64::{ }; use cranelift_codegen::{settings, MachBuffer, MachInstEmit, Reg, Writable}; use crossbeam::queue::SegQueue; -use isla_lib::executor::{self, freeze_frame, LocalFrame, TaskState}; use isla_lib::init::{initialize_architecture, Initialized}; use isla_lib::ir::{AssertionMode, Def, IRTypeInfo, Name, Symtab, Ty, Val}; use isla_lib::ir_lexer::new_ir_lexer; @@ -25,6 +24,10 @@ use isla_lib::{ error::{ExecError, IslaError}, memory::Address, }; +use isla_lib::{ + executor::{self, freeze_frame, LocalFrame, TaskState}, + ir::linearize, +}; use sha2::{Digest, Sha256}; use std::io::prelude::*; use std::io::BufWriter; @@ -69,6 +72,24 @@ fn main() -> anyhow::Result<()> { Err(msg) => anyhow::bail!(msg), }; + let linearize_functions = vec![ + // See: https://github.com/rems-project/isla-testgen/blob/a9759247bfdff9c9c39d95a4cfd85318e5bf50fe/c86-command + //"fdiv_int", + "bool_to_bits", + "bits_to_bool", + //"bit_to_bool", + //"isEven", + "signed_byte_p_int", + "zf_spec", + //"b_xor", + //"logand_int", + //"not_bit", + //"floor2", + ]; + for name in linearize_functions { + linearize_function(&mut arch, name, &mut symtab)?; + } + let use_model_reg_init = true; let iarch = initialize_architecture( &mut arch, @@ -508,3 +529,45 @@ fn parse_ir<'a, 'input, B: BV>( Err(_) => Err(anyhow::Error::msg("bad")), } } + +fn linearize_function<'ir, B: BV>( + arch: &mut Vec>, + name: &str, + symtab: &mut Symtab<'ir>, +) -> anyhow::Result<()> { + log!(log::VERBOSE, format!("linearize function {}", name)); + + // Lookup function name. + let target = match symtab.get(&zencode::encode(name)) { + Some(t) => t, + None => anyhow::bail!("function {} could not be found", name), + }; + + // Find signature. + let (_args, ret) = lookup_signature(arch, target)?; + + // Rewrite. + for def in arch.iter_mut() { + if let Def::Fn(f, _, body) = def { + if *f == target { + let rewritten = linearize::linearize(body.to_vec(), &ret, symtab); + *body = rewritten; + } + } + } + + Ok(()) +} + +fn lookup_signature( + arch: &Vec>, + target: Name, +) -> anyhow::Result<(Vec>, Ty)> { + for def in arch { + match def { + Def::Val(f, args, ret) if *f == target => return Ok((args.clone(), ret.clone())), + _ => (), + } + } + anyhow::bail!("could not find type signature") +} From b68e55bc929d134ab1a3261efadd49406860c379 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Sun, 24 Dec 2023 13:48:21 -0500 Subject: [PATCH 18/73] disable simplify::hide_initialization This doesn't work the same on x64 as it does on arm, and ends up deleting important parts of the trace. --- cranelift/isle/veri/veri_engine/src/x64.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cranelift/isle/veri/veri_engine/src/x64.rs b/cranelift/isle/veri/veri_engine/src/x64.rs index f680bbf71ad5..2acd6dcf4319 100644 --- a/cranelift/isle/veri/veri_engine/src/x64.rs +++ b/cranelift/isle/veri/veri_engine/src/x64.rs @@ -318,7 +318,7 @@ fn trace_opcode<'ir, B: BV>( loop { match queue.pop() { Some(Ok((_, mut events))) => { - simplify::hide_initialization(&mut events); + // simplify::hide_initialization(&mut events); simplify::remove_extra_register_fields(&mut events); simplify::remove_repeated_register_reads(&mut events); simplify::remove_unused_register_assumptions(&mut events); From 72fa49900f7df719547243e2503d88fe34f9875b Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Wed, 27 Dec 2023 07:09:17 -0500 Subject: [PATCH 19/73] emit: add a selection of instructions --- cranelift/codegen/src/isa/aarch64/inst/mod.rs | 6 +- cranelift/codegen/src/lib.rs | 6 +- cranelift/isle/veri/veri_engine/src/emit.rs | 145 +++++++++++++++--- 3 files changed, 135 insertions(+), 22 deletions(-) diff --git a/cranelift/codegen/src/isa/aarch64/inst/mod.rs b/cranelift/codegen/src/isa/aarch64/inst/mod.rs index b510fa9bd29f..811ce71693d7 100644 --- a/cranelift/codegen/src/isa/aarch64/inst/mod.rs +++ b/cranelift/codegen/src/isa/aarch64/inst/mod.rs @@ -1191,7 +1191,11 @@ fn mem_finalize_for_show(mem: &AMode, state: &EmitState) -> (String, AMode) { } impl Inst { - fn print_with_state(&self, state: &mut EmitState, allocs: &mut AllocationConsumer) -> String { + pub fn print_with_state( + &self, + state: &mut EmitState, + allocs: &mut AllocationConsumer, + ) -> String { let mut empty_allocs = AllocationConsumer::default(); fn op_name(alu_op: ALUOp) -> &'static str { diff --git a/cranelift/codegen/src/lib.rs b/cranelift/codegen/src/lib.rs index b95a75e3f70f..1a5993ee0ad5 100644 --- a/cranelift/codegen/src/lib.rs +++ b/cranelift/codegen/src/lib.rs @@ -60,9 +60,9 @@ pub use crate::machinst::buffer::{ MachTextSectionBuilder, MachTrap, }; pub use crate::machinst::{ - CompiledCode, Final, MachBuffer, MachBufferFinalized, MachInst, MachInstEmit, - MachInstEmitState, MachLabel, Reg, TextSectionBuilder, VCodeConstantData, VCodeConstants, - Writable, + AllocationConsumer, CompiledCode, Final, MachBuffer, MachBufferFinalized, MachInst, + MachInstEmit, MachInstEmitState, MachLabel, Reg, TextSectionBuilder, VCodeConstantData, + VCodeConstants, Writable, }; mod alias_analysis; diff --git a/cranelift/isle/veri/veri_engine/src/emit.rs b/cranelift/isle/veri/veri_engine/src/emit.rs index 06db57ca3120..110c3f853bc2 100644 --- a/cranelift/isle/veri/veri_engine/src/emit.rs +++ b/cranelift/isle/veri/veri_engine/src/emit.rs @@ -1,7 +1,9 @@ use anyhow::Context as _; use clap::Parser; +use cranelift_codegen::ir::types::I32; use cranelift_codegen::isa::aarch64::inst::*; use cranelift_codegen::settings; +use cranelift_codegen::AllocationConsumer; use cranelift_codegen::MachBuffer; use cranelift_codegen::MachInstEmit; use crossbeam::queue::SegQueue; @@ -68,25 +70,130 @@ fn main() -> anyhow::Result<()> { use_model_reg_init, ); - // Assemble an instruction. - let inst = Inst::AluRRR { - alu_op: ALUOp::Add, - size: OperandSize::Size64, - rd: writable_xreg(4), - rn: xreg(5), - rm: xreg(6), - }; + // Assemble and trace instructions. + let insts = vec![ + Inst::AluRRR { + alu_op: ALUOp::Add, + size: OperandSize::Size64, + rd: writable_xreg(4), + rn: xreg(5), + rm: xreg(6), + }, + Inst::AluRRRR { + alu_op: ALUOp3::MSub, + size: OperandSize::Size32, + rd: writable_xreg(1), + rn: xreg(2), + rm: xreg(3), + ra: xreg(4), + }, + Inst::AluRRImmLogic { + alu_op: ALUOp::Eor, + size: OperandSize::Size32, + rd: writable_xreg(1), + rn: xreg(5), + imml: ImmLogic::maybe_from_u64(0x00007fff, I32).unwrap(), + }, + Inst::AluRRRShift { + alu_op: ALUOp::SubS, + size: OperandSize::Size64, + rd: writable_xreg(10), + rn: xreg(11), + rm: xreg(12), + shiftop: ShiftOpAndAmt::new( + ShiftOp::LSL, + ShiftOpShiftImm::maybe_from_shift(23).unwrap(), + ), + }, + Inst::AluRRRExtend { + alu_op: ALUOp::SubS, + size: OperandSize::Size64, + rd: writable_zero_reg(), + rn: stack_reg(), + rm: xreg(12), + extendop: ExtendOp::UXTX, + }, + // TODO: BitRR + // Inst::BitRR { + // op: BitOp::Rev64, + // size: OperandSize::Size64, + // rd: writable_xreg(1), + // rn: xreg(10), + // }, + Inst::Mov { + size: OperandSize::Size64, + rd: writable_xreg(8), + rm: xreg(9), + }, + Inst::CSel { + rd: writable_xreg(10), + rn: xreg(12), + rm: xreg(14), + cond: Cond::Hs, + }, + Inst::CCmp { + size: OperandSize::Size64, + rn: xreg(22), + rm: xreg(1), + nzcv: NZCV::new(false, false, true, true), + cond: Cond::Eq, + }, + Inst::AluRRImmShift { + alu_op: ALUOp::Lsr, + size: OperandSize::Size64, + rd: writable_xreg(10), + rn: xreg(11), + immshift: ImmShift::maybe_from_u64(57).unwrap(), + }, + Inst::AluRRImm12 { + alu_op: ALUOp::SubS, + size: OperandSize::Size32, + rd: writable_xreg(7), + rn: xreg(8), + imm12: Imm12 { + bits: 0x123, + shift12: false, + }, + }, + Inst::Extend { + rd: writable_xreg(1), + rn: xreg(2), + signed: true, + from_bits: 8, + to_bits: 32, + }, + Inst::AluRRRExtend { + alu_op: ALUOp::Sub, + size: OperandSize::Size64, + rd: writable_xreg(20), + rn: xreg(21), + rm: xreg(22), + extendop: ExtendOp::UXTW, + }, + ]; - let opcodes = opcodes(&inst); - assert_eq!(opcodes.len(), 1); + for inst in insts { + let opcodes = opcodes(&inst); + assert_eq!(opcodes.len(), 1); + let opcode = opcodes[0]; - // ISLA trace. - let paths = trace_opcode(opcodes[0], &iarch)?; + // Show assembly. + let asm = + inst.print_with_state(&mut EmitState::default(), &mut AllocationConsumer::new(&[])); - // Dump. - for events in paths { - let filtered = tree_shake(&events); - write_events(&filtered, &iarch)?; + println!("--------------------------------------------------"); + println!("inst = {inst:?}"); + println!("opcode = {opcode:08x}"); + println!("asm = {asm}"); + + // ISLA trace. + let paths = trace_opcode(opcode, &iarch)?; + + // Dump. + for events in paths { + let filtered = tree_shake(&events); + write_events(&filtered, &iarch)?; + } } Ok(()) @@ -215,7 +322,9 @@ fn exp_uses(exp: &smtlib::Exp) -> HashSet { use smtlib::Exp::*; match exp { Var(sym) => HashSet::from([*sym]), - //Bits(_) | Bits64(_) | Enum(_) | Bool(_) | FPConstant(..) | FPRoundingMode(_) => (), + Bits(_) | Bits64(_) | Enum(_) | Bool(_) | FPConstant(..) | FPRoundingMode(_) => { + HashSet::new() + } Not(exp) | Bvnot(exp) | Bvneg(exp) @@ -298,7 +407,7 @@ fn exp_uses(exp: &smtlib::Exp) -> HashSet { // uses_in_exp(uses, y); // uses_in_exp(uses, z) //} - _ => todo!(), + _ => todo!("not yet implemented expression: {:?}", exp), } } From f379221c44440f62a98f3b4887b687cb68cf783d Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Wed, 27 Dec 2023 12:34:09 -0500 Subject: [PATCH 20/73] optionally show full traces --- cranelift/isle/veri/veri_engine/src/emit.rs | 27 +++++++++++---------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/cranelift/isle/veri/veri_engine/src/emit.rs b/cranelift/isle/veri/veri_engine/src/emit.rs index 110c3f853bc2..940ab9042cc6 100644 --- a/cranelift/isle/veri/veri_engine/src/emit.rs +++ b/cranelift/isle/veri/veri_engine/src/emit.rs @@ -1,5 +1,5 @@ use anyhow::Context as _; -use clap::Parser; +use clap::{ArgAction, Parser}; use cranelift_codegen::ir::types::I32; use cranelift_codegen::isa::aarch64::inst::*; use cranelift_codegen::settings; @@ -36,6 +36,10 @@ struct Options { /// ISA config file. #[clap(long)] isa_config: PathBuf, + + /// Filter relevant events from the trace. + #[clap(long, action=ArgAction::SetTrue)] + filter: bool, } fn main() -> anyhow::Result<()> { @@ -108,8 +112,8 @@ fn main() -> anyhow::Result<()> { Inst::AluRRRExtend { alu_op: ALUOp::SubS, size: OperandSize::Size64, - rd: writable_zero_reg(), - rn: stack_reg(), + rd: writable_xreg(10), + rn: xreg(11), rm: xreg(12), extendop: ExtendOp::UXTX, }, @@ -162,14 +166,6 @@ fn main() -> anyhow::Result<()> { from_bits: 8, to_bits: 32, }, - Inst::AluRRRExtend { - alu_op: ALUOp::Sub, - size: OperandSize::Size64, - rd: writable_xreg(20), - rn: xreg(21), - rm: xreg(22), - extendop: ExtendOp::UXTW, - }, ]; for inst in insts { @@ -191,8 +187,12 @@ fn main() -> anyhow::Result<()> { // Dump. for events in paths { - let filtered = tree_shake(&events); - write_events(&filtered, &iarch)?; + let events = if options.filter { + tree_shake(&events) + } else { + events + }; + write_events(&events, &iarch)?; } } @@ -488,6 +488,7 @@ fn tree_shake(events: &Vec>) -> Vec> { // Mark uses live. for u in uses(&event) { // Lookup definition of this dependency. + assert!(defn_idx.contains_key(&u), "no definition for {:?}", u); let ui = defn_idx[&u]; if live.contains(&ui) { continue; From ba61ba7464d8771edd44469c953e4c3362498f44 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Fri, 29 Dec 2023 09:20:26 -0500 Subject: [PATCH 21/73] update emit tool to use isla options --- Cargo.lock | 269 +++++++++++++++++--- cranelift/isle/veri/veri_engine/Cargo.toml | 1 + cranelift/isle/veri/veri_engine/src/emit.rs | 94 ++----- 3 files changed, 257 insertions(+), 107 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dd3ff4ea8867..772bee2f6caf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,7 +8,7 @@ version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ - "gimli", + "gimli 0.28.0", ] [[package]] @@ -23,7 +23,7 @@ version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" dependencies = [ - "getrandom", + "getrandom 0.2.10", "once_cell", "version_check", ] @@ -343,7 +343,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "577de6cff7c2a47d6b13efe5dd28bf116bd7f8f7db164ea95b7cc2640711f522" dependencies = [ "ambient-authority", - "rand", + "rand 0.8.5", ] [[package]] @@ -365,7 +365,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b9e3348a3510c4619b4c7a7bcdef09a71221da18f266bda3ed6b9aea2c509e2" dependencies = [ "cap-std", - "rand", + "rand 0.8.5", "rustix", "uuid", ] @@ -574,7 +574,7 @@ name = "command-tests" version = "0.0.0" dependencies = [ "anyhow", - "getrandom", + "getrandom 0.2.10", "wit-bindgen", ] @@ -677,7 +677,7 @@ dependencies = [ "cranelift-entity", "cranelift-isle", "criterion", - "gimli", + "gimli 0.28.0", "hashbrown 0.14.1", "log", "regalloc2", @@ -733,7 +733,7 @@ dependencies = [ "cranelift-wasm", "file-per-thread-logger", "filecheck", - "gimli", + "gimli 0.28.0", "log", "num_cpus", "serde", @@ -1286,6 +1286,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + [[package]] name = "fallible-iterator" version = "0.3.0" @@ -1497,6 +1503,26 @@ dependencies = [ "version_check", ] +[[package]] +name = "getopts" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + [[package]] name = "getrandom" version = "0.2.10" @@ -1505,7 +1531,18 @@ checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "gimli" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" +dependencies = [ + "fallible-iterator 0.2.0", + "indexmap 1.9.3", + "stable_deref_trait", ] [[package]] @@ -1514,7 +1551,7 @@ version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" dependencies = [ - "fallible-iterator", + "fallible-iterator 0.3.0", "indexmap 2.0.2", "stable_deref_trait", ] @@ -1525,6 +1562,17 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +[[package]] +name = "goblin" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32401e89c6446dcd28185931a01b1093726d0356820ac744023e6850689bf926" +dependencies = [ + "log", + "plain", + "scroll", +] + [[package]] name = "h2" version = "0.3.21" @@ -1787,6 +1835,63 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "isla" +version = "0.2.0" +dependencies = [ + "bincode", + "crossbeam", + "getopts", + "id-arena", + "isla-axiomatic", + "isla-cat", + "isla-elf", + "isla-lib", + "isla-mml", + "rand 0.7.3", + "serde", + "sha2 0.8.2", + "toml", +] + +[[package]] +name = "isla-axiomatic" +version = "0.2.0" +dependencies = [ + "crossbeam", + "goblin", + "isla-cat", + "isla-lib", + "isla-mml", + "isla-sexp", + "lalrpop", + "lalrpop-util", + "lazy_static", + "regex", + "serde", + "toml", +] + +[[package]] +name = "isla-cat" +version = "0.2.0" +dependencies = [ + "lalrpop", + "lalrpop-util", + "lazy_static", + "regex", +] + +[[package]] +name = "isla-elf" +version = "0.2.0" +dependencies = [ + "gimli 0.26.2", + "goblin", + "isla-lib", + "lazy_static", +] + [[package]] name = "isla-lib" version = "0.2.0" @@ -1808,6 +1913,28 @@ dependencies = [ "z3-sys", ] +[[package]] +name = "isla-mml" +version = "0.2.0" +dependencies = [ + "id-arena", + "isla-lib", + "lalrpop", + "lalrpop-util", + "lazy_static", + "regex", +] + +[[package]] +name = "isla-sexp" +version = "0.2.0" +dependencies = [ + "isla-mml", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "isle-fuzz" version = "0.0.0" @@ -2083,7 +2210,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.48.0", ] @@ -2299,6 +2426,12 @@ version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + [[package]] name = "plotters" version = "0.3.5" @@ -2403,8 +2536,8 @@ dependencies = [ "bitflags 2.4.0", "lazy_static", "num-traits", - "rand", - "rand_chacha", + "rand 0.8.5", + "rand_chacha 0.3.1", "rand_xorshift", "regex-syntax 0.7.5", "rusty-fork", @@ -2447,6 +2580,19 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", +] + [[package]] name = "rand" version = "0.8.5" @@ -2454,8 +2600,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", ] [[package]] @@ -2465,7 +2621,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", ] [[package]] @@ -2474,7 +2639,16 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.10", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", ] [[package]] @@ -2483,7 +2657,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" dependencies = [ - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -2546,7 +2720,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "getrandom", + "getrandom 0.2.10", "redox_syscall 0.2.16", "thiserror", ] @@ -2627,7 +2801,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9166d72162de3575f950507683fac47e30f6f2c3836b71b7fbc61aa517c9c5f4" dependencies = [ - "rand", + "rand 0.8.5", ] [[package]] @@ -2733,6 +2907,26 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "scroll" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda28d4b4830b807a8b43f7b0e6b5df875311b3e7621d84577188c175b6ec1ec" +dependencies = [ + "scroll_derive", +] + +[[package]] +name = "scroll_derive" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aaaae8f38bb311444cfb7f1979af0bc9240d95795f75f9ceddf6a59b79ceffa0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "sct" version = "0.7.0" @@ -2832,7 +3026,7 @@ checksum = "4ee9977fa98489d9006f4ab26fc5cbe2a139985baed09d2ec08dee6e506fc496" dependencies = [ "cfg-if", "libc", - "rand", + "rand 0.8.5", "winapi", ] @@ -3375,7 +3569,7 @@ version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" dependencies = [ - "getrandom", + "getrandom 0.2.10", ] [[package]] @@ -3403,6 +3597,7 @@ dependencies = [ "crossbeam", "easy-smt", "env_logger 0.10.0", + "isla", "isla-lib", "itertools", "log", @@ -3460,6 +3655,12 @@ dependencies = [ "try-lock", ] +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -3527,7 +3728,7 @@ version = "14.0.0" dependencies = [ "byte-array-literals", "object", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "wasm-encoder", "wit-bindgen", ] @@ -3546,7 +3747,7 @@ version = "0.0.0" dependencies = [ "libc", "once_cell", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "wit-bindgen", ] @@ -3653,7 +3854,7 @@ checksum = "ee038ee28c816dfeabb992ba765d801f721a6d1b097cba0f941c184454616d92" dependencies = [ "egg", "log", - "rand", + "rand 0.8.5", "thiserror", "wasm-encoder", "wasmparser", @@ -3949,7 +4150,7 @@ dependencies = [ "cranelift-frontend", "cranelift-native", "cranelift-wasm", - "gimli", + "gimli 0.28.0", "log", "object", "target-lexicon", @@ -3968,7 +4169,7 @@ dependencies = [ "cranelift-codegen", "cranelift-control", "cranelift-native", - "gimli", + "gimli 0.28.0", "object", "target-lexicon", "wasmtime-environ", @@ -3982,7 +4183,7 @@ dependencies = [ "clap 4.4.6", "cranelift-entity", "env_logger 0.10.0", - "gimli", + "gimli 0.28.0", "indexmap 2.0.2", "log", "object", @@ -4059,7 +4260,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "rand", + "rand 0.8.5", "smallvec", "target-lexicon", "wasmparser", @@ -4077,7 +4278,7 @@ dependencies = [ "component-test-util", "env_logger 0.10.0", "log", - "rand", + "rand 0.8.5", "rayon", "target-lexicon", "tempfile", @@ -4103,7 +4304,7 @@ dependencies = [ "bincode", "cfg-if", "cpp_demangle", - "gimli", + "gimli 0.28.0", "ittapi", "log", "object", @@ -4155,7 +4356,7 @@ dependencies = [ "once_cell", "paste", "proptest", - "rand", + "rand 0.8.5", "rustix", "sptr", "wasm-encoder", @@ -4264,7 +4465,7 @@ version = "14.0.0" dependencies = [ "anyhow", "log", - "rand", + "rand 0.8.5", "wasi-common", "wasmtime", "wasmtime-wasi", @@ -4286,7 +4487,7 @@ version = "14.0.0" dependencies = [ "anyhow", "cranelift-codegen", - "gimli", + "gimli 0.28.0", "object", "target-lexicon", "wasmparser", @@ -4470,7 +4671,7 @@ version = "0.12.0" dependencies = [ "anyhow", "cranelift-codegen", - "gimli", + "gimli 0.28.0", "regalloc2", "smallvec", "target-lexicon", diff --git a/cranelift/isle/veri/veri_engine/Cargo.toml b/cranelift/isle/veri/veri_engine/Cargo.toml index 2dab78f578d6..1b6546dd9f83 100644 --- a/cranelift/isle/veri/veri_engine/Cargo.toml +++ b/cranelift/isle/veri/veri_engine/Cargo.toml @@ -30,6 +30,7 @@ cranelift-isle = { path = "../../isle" } cranelift-codegen = { path = "../../../codegen" } cranelift-reader = { path = "../../../reader" } cranelift-codegen-meta = { path = "../../../codegen/meta" } +isla = { path = "../../../../../isla" } isla-lib = { path = "../../../../../isla/isla-lib" } anyhow = { workspace = true } veri_ir = { path = "../veri_ir" } diff --git a/cranelift/isle/veri/veri_engine/src/emit.rs b/cranelift/isle/veri/veri_engine/src/emit.rs index 940ab9042cc6..52282da561e3 100644 --- a/cranelift/isle/veri/veri_engine/src/emit.rs +++ b/cranelift/isle/veri/veri_engine/src/emit.rs @@ -1,5 +1,3 @@ -use anyhow::Context as _; -use clap::{ArgAction, Parser}; use cranelift_codegen::ir::types::I32; use cranelift_codegen::isa::aarch64::inst::*; use cranelift_codegen::settings; @@ -7,63 +5,39 @@ use cranelift_codegen::AllocationConsumer; use cranelift_codegen::MachBuffer; use cranelift_codegen::MachInstEmit; use crossbeam::queue::SegQueue; +use isla::opts; use isla_lib::bitvector::{b64::B64, BV}; -use isla_lib::config::ISAConfig; use isla_lib::error::IslaError; use isla_lib::executor::{self, LocalFrame, TaskState}; use isla_lib::init::{initialize_architecture, Initialized}; -use isla_lib::ir::{AssertionMode, Def, IRTypeInfo, Name, Symtab, Val}; -use isla_lib::ir_lexer::new_ir_lexer; -use isla_lib::ir_parser; +use isla_lib::ir::{AssertionMode, Val}; use isla_lib::memory::Memory; use isla_lib::simplify::{self, WriteOpts}; use isla_lib::smt::smtlib; use isla_lib::smt::{self, Checkpoint, Event, Solver}; use sha2::{Digest, Sha256}; use std::collections::{HashMap, HashSet}; -use std::fs::File; use std::io::prelude::*; -use std::io::{self, BufWriter, Read}; -use std::path::{Path, PathBuf}; +use std::io::BufWriter; +use std::path::PathBuf; use std::sync::Arc; -#[derive(Parser)] -struct Options { - /// Architecture definition. - #[clap(long)] - arch: PathBuf, - - /// ISA config file. - #[clap(long)] - isa_config: PathBuf, - - /// Filter relevant events from the trace. - #[clap(long, action=ArgAction::SetTrue)] - filter: bool, -} - fn main() -> anyhow::Result<()> { - let options = Options::parse(); + // Command-line options. + let mut opts = opts::common_opts(); + opts.optflag("", "filter", "filter relevant events from the trace"); - // Parse ISLA Architecture. - let contents = read_to_string(&options.arch)?; - let mut symtab = Symtab::new(); - let mut arch = parse_ir::(&contents, &mut symtab)?; - - // ISLA ISA Config. + // Build ISLA architecture. let mut hasher = Sha256::new(); - let type_info = IRTypeInfo::new(&arch); - let isa_config = match ISAConfig::::from_file( - &mut hasher, - &options.isa_config, - None, - &symtab, - &type_info, - ) { - Ok(isa_config) => isa_config, - Err(msg) => anyhow::bail!(msg), - }; - + let (matches, arch) = opts::parse::(&mut hasher, &opts); + let opts::CommonOpts { + num_threads: _, + mut arch, + symtab, + type_info, + isa_config, + source_path: _, + } = opts::parse_with_arch(&mut hasher, &opts, &matches, &arch); let use_model_reg_init = true; let iarch = initialize_architecture( &mut arch, @@ -184,14 +158,16 @@ fn main() -> anyhow::Result<()> { // ISLA trace. let paths = trace_opcode(opcode, &iarch)?; + println!("num paths = {}", paths.len()); // Dump. for events in paths { - let events = if options.filter { + let events = if matches.opt_present("filter") { tree_shake(&events) } else { events }; + println!(""); write_events(&events, &iarch)?; } } @@ -232,7 +208,7 @@ fn trace_opcode<'ir, B: BV>( let opcode_val = Val::Bits(B::from_u32(opcode)); - let footprint_function = "zisla_footprint"; + let footprint_function = "zisla_footprint_no_init"; let function_id = shared_state.symtab.lookup(&footprint_function); let (args, ret_ty, instrs) = shared_state.functions.get(&function_id).unwrap(); let memory = Memory::new(); @@ -521,31 +497,3 @@ fn write_events<'ir, B: BV>( Ok(()) } - -fn parse_ir<'a, 'input, B: BV>( - contents: &'input str, - symtab: &'a mut Symtab<'input>, -) -> anyhow::Result>> { - match ir_parser::IrParser::new().parse(symtab, new_ir_lexer(&contents)) { - Ok(ir) => Ok(ir), - Err(_) => Err(anyhow::Error::msg("bad")), - } -} - -/// Read an entire file into a string. -fn read_to_string>(path: P) -> anyhow::Result { - let mut buffer = String::new(); - let path = path.as_ref(); - if path == Path::new("-") { - let stdin = io::stdin(); - let mut stdin = stdin.lock(); - stdin - .read_to_string(&mut buffer) - .context("failed to read stdin to string")?; - } else { - let mut file = File::open(path)?; - file.read_to_string(&mut buffer) - .with_context(|| format!("failed to read {} to string", path.display()))?; - } - Ok(buffer) -} From e7897daeb5f2278a61c4257ccc459f6932efcfda Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Fri, 29 Dec 2023 10:18:05 -0500 Subject: [PATCH 22/73] support filtering for ITE and struct reads --- cranelift/isle/veri/veri_engine/src/emit.rs | 41 ++++++++++++--------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/cranelift/isle/veri/veri_engine/src/emit.rs b/cranelift/isle/veri/veri_engine/src/emit.rs index 52282da561e3..d95bb0c877bd 100644 --- a/cranelift/isle/veri/veri_engine/src/emit.rs +++ b/cranelift/isle/veri/veri_engine/src/emit.rs @@ -270,24 +270,21 @@ fn trace_opcode<'ir, B: BV>( Ok(paths) } -fn event_writes(event: &Event) -> Option { +fn event_writes(event: &Event) -> HashSet { match event { Event::Smt(def, _, _) => match def { - smtlib::Def::DefineConst(v, _) => Some(*v), - _ => None, + smtlib::Def::DefineConst(v, _) => HashSet::from([*v]), + _ => HashSet::new(), }, - Event::ReadReg(_, _, val) => match val { - Val::Symbolic(sym) => Some(*sym), - _ => None, - }, - _ => None, + Event::ReadReg(_, _, val) => val_uses(val), + _ => HashSet::new(), } } fn defns(events: &Vec>) -> HashMap { let mut defn_idx = HashMap::new(); for (i, event) in events.iter().enumerate() { - if let Some(sym) = event_writes(event) { + for sym in event_writes(event) { defn_idx.insert(sym, i); } } @@ -343,11 +340,13 @@ fn exp_uses(exp: &smtlib::Exp) -> HashSet { let rhs_uses = exp_uses(rhs); &lhs_uses | &rhs_uses } - //Ite(cond, then_exp, else_exp) => { - // uses_in_exp(uses, cond); - // uses_in_exp(uses, then_exp); - // uses_in_exp(uses, else_exp) - //} + Ite(cond, then_exp, else_exp) => { + let cond_uses = exp_uses(cond); + let then_uses = exp_uses(then_exp); + let else_uses = exp_uses(else_exp); + let uses = &cond_uses | &then_uses; + &uses | &else_uses + } //App(f, args) => { // uses.insert(*f, uses.get(f).unwrap_or(&0) + 1); // for arg in args { @@ -400,17 +399,23 @@ fn smt_def_uses(def: &smtlib::Def) -> HashSet { fn val_uses(val: &Val) -> HashSet { // See: simplify::uses_in_value + use Val::*; match val { - Val::Symbolic(sym) => HashSet::from([*sym]), + Symbolic(sym) => HashSet::from([*sym]), // MixedBits(segments) => segments.iter().for_each(|segment| match segment { // BitsSegment::Symbolic(v) => { // uses.insert(*v, uses.get(v).unwrap_or(&0) + 1); // } // BitsSegment::Concrete(_) => (), // }), - // I64(_) | I128(_) | Bool(_) | Bits(_) | Enum(_) | String(_) | Unit | Ref(_) | Poison => (), + I64(_) | I128(_) | Bool(_) | Bits(_) | Enum(_) | String(_) | Unit | Ref(_) | Poison => { + HashSet::new() + } // List(vals) | Vector(vals) => vals.iter().for_each(|val| uses_in_value(uses, val)), - // Struct(fields) => fields.iter().for_each(|(_, val)| uses_in_value(uses, val)), + Struct(fields) => fields + .iter() + .map(|(_, val)| val_uses(val)) + .fold(HashSet::new(), |acc, uses| &acc | &uses), // Ctor(_, val) => uses_in_value(uses, val), // SymbolicCtor(v, possibilities) => { // uses.insert(*v, uses.get(v).unwrap_or(&0) + 1); @@ -418,7 +423,7 @@ fn val_uses(val: &Val) -> HashSet { // .iter() // .for_each(|(_, val)| uses_in_value(uses, val)) // } - _ => HashSet::new(), + _ => todo!("not yet implemented value: {:?}", val), } } From 837e59b3c39971452d0a7e81eb87cf8ff43706ef Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Fri, 29 Dec 2023 12:24:55 -0500 Subject: [PATCH 23/73] post-filter simplify --- cranelift/isle/veri/veri_engine/src/emit.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/cranelift/isle/veri/veri_engine/src/emit.rs b/cranelift/isle/veri/veri_engine/src/emit.rs index d95bb0c877bd..f296e970027a 100644 --- a/cranelift/isle/veri/veri_engine/src/emit.rs +++ b/cranelift/isle/veri/veri_engine/src/emit.rs @@ -480,12 +480,20 @@ fn tree_shake(events: &Vec>) -> Vec> { } } - events + // Filter down to live events. + let mut events: Vec<_> = events .iter() .enumerate() .filter_map(|(i, event)| if live.contains(&i) { Some(event) } else { None }) .cloned() - .collect() + .collect(); + + // Simplify pass. + events.reverse(); + simplify::propagate_forwards_used_once(&mut events); + events.reverse(); + + events } fn write_events<'ir, B: BV>( From 447f355df5d41a791b27a9546cf4813ecf767be4 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Fri, 29 Dec 2023 12:30:59 -0500 Subject: [PATCH 24/73] account for PSTATE register writes --- cranelift/isle/veri/veri_engine/src/emit.rs | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/cranelift/isle/veri/veri_engine/src/emit.rs b/cranelift/isle/veri/veri_engine/src/emit.rs index f296e970027a..652f2c6c0156 100644 --- a/cranelift/isle/veri/veri_engine/src/emit.rs +++ b/cranelift/isle/veri/veri_engine/src/emit.rs @@ -444,18 +444,15 @@ fn tree_shake(events: &Vec>) -> Vec> { let mut live = HashSet::new(); for (i, event) in events.iter().enumerate() { match event { - Event::WriteReg(_, _, val) => match val { - Val::Symbolic(sym) => { - // Mark live. - live.insert(i); - - // Push the variable to be visited. - let d = defn_idx[&sym]; - live.insert(d); - work_list.push(d); - } - _ => continue, - }, + Event::WriteReg(_, _, val) => val_uses(val).iter().for_each(|sym| { + // Mark live. + live.insert(i); + + // Push the variable to be visited. + let d = defn_idx[&sym]; + live.insert(d); + work_list.push(d); + }), _ => continue, }; } From 0c06bfd53dc8bcde8aff5ef5b37117d26293f635 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Sat, 30 Dec 2023 06:19:18 -0500 Subject: [PATCH 25/73] type inference: support "extra" spec variables --- .../veri/veri_engine/src/type_inference.rs | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/cranelift/isle/veri/veri_engine/src/type_inference.rs b/cranelift/isle/veri/veri_engine/src/type_inference.rs index 67dfad805fcf..8520e0c1720b 100644 --- a/cranelift/isle/veri/veri_engine/src/type_inference.rs +++ b/cranelift/isle/veri/veri_engine/src/type_inference.rs @@ -26,8 +26,8 @@ struct RuleParseTree { bv_constraints: HashSet, ty_vars: HashMap, - quantified_vars: HashSet<(String, u32)>, - free_vars: HashSet<(String, u32)>, + quantified_vars: HashMap, + free_vars: HashMap, // Used to check distinct models term_input_bvs: Vec, // Used for custom verification conditions @@ -178,8 +178,8 @@ fn type_annotations_using_rule<'a>( var_constraints: HashSet::new(), bv_constraints: HashSet::new(), ty_vars: HashMap::new(), - quantified_vars: HashSet::new(), - free_vars: HashSet::new(), + quantified_vars: HashMap::new(), + free_vars: HashMap::new(), term_input_bvs: vec![], term_args: vec![], assumptions: vec![], @@ -380,6 +380,13 @@ fn add_annotation_constraints( tree.next_type_var += 1; } let name = format!("{}__{}__{}", annotation_info.term, x, t); + + // Support the introduction of extra variables in the specification. + // + // TODO(mbm): understand whether this needs to be in quantified, free or both? + tree.quantified_vars.insert(name.clone(), t); + tree.free_vars.insert(name.clone(), t); + (veri_ir::Expr::Terminal(veri_ir::Terminal::Var(name)), t) } annotation_ir::Expr::Const(c, ..) => { @@ -1362,8 +1369,6 @@ fn add_annotation_constraints( _ => todo!("expr {:#?} not yet implemented", expr), }; tree.ty_vars.insert(e.clone(), t); - // let fmt = format!("{}:\t{:?}", t, e); - // dbg!(fmt); (e, t) } @@ -1445,8 +1450,8 @@ fn add_rule_constraints( let e = match &curr.construct { TypeVarConstruct::Var => { tree.quantified_vars - .insert((curr.ident.clone(), curr.type_var)); - tree.free_vars.insert((curr.ident.clone(), curr.type_var)); + .insert(curr.ident.clone(), curr.type_var); + tree.free_vars.insert(curr.ident.clone(), curr.type_var); Some(veri_ir::Expr::Terminal(veri_ir::Terminal::Var( curr.ident.clone(), ))) @@ -1475,7 +1480,7 @@ fn add_rule_constraints( } TypeVarConstruct::And => { tree.quantified_vars - .insert((curr.ident.clone(), curr.type_var)); + .insert(curr.ident.clone(), curr.type_var); let first = &children[0]; for (i, e) in children.iter().enumerate() { if i != 0 { @@ -1490,7 +1495,7 @@ fn add_rule_constraints( } TypeVarConstruct::Let(bound) => { tree.quantified_vars - .insert((curr.ident.clone(), curr.type_var)); + .insert(curr.ident.clone(), curr.type_var); for (e, s) in children.iter().zip(bound) { tree.assumptions.push(veri_ir::Expr::Binary( veri_ir::BinaryOp::Eq, @@ -1510,7 +1515,7 @@ fn add_rule_constraints( print!(" {}", term_name); tree.quantified_vars - .insert((curr.ident.clone(), curr.type_var)); + .insert(curr.ident.clone(), curr.type_var); let a = annotation_env.get_annotation_for_term(term_id); if a.is_none() { println!("\nSkipping rule with unannotated term: {}", term_name); @@ -1601,7 +1606,7 @@ fn add_rule_constraints( annotation_info.term, arg.name, annotation_type_var ); tree.quantified_vars - .insert((arg_name.clone(), annotation_type_var)); + .insert(arg_name.clone(), annotation_type_var); tree.assumptions.push(veri_ir::Expr::Binary( veri_ir::BinaryOp::Eq, Box::new(child.clone()), @@ -1616,7 +1621,7 @@ fn add_rule_constraints( "{}__{}__{}", annotation_info.term, annotation.sig.ret.name, ret_var ); - tree.quantified_vars.insert((ret_name.clone(), ret_var)); + tree.quantified_vars.insert(ret_name.clone(), ret_var); tree.assumptions.push(veri_ir::Expr::Binary( veri_ir::BinaryOp::Eq, Box::new(veri_ir::Expr::Terminal(veri_ir::Terminal::Var( @@ -2258,7 +2263,7 @@ fn create_parse_tree_expr( tree.varid_to_type_var_map.insert(*varid, ty_var); children.push(subpat_node); let ident = format!("{}__clif{}__{}", var, varid.index(), ty_var); - tree.quantified_vars.insert((ident.clone(), ty_var)); + tree.quantified_vars.insert(ident.clone(), ty_var); bound.push(ident); } let body = create_parse_tree_expr(rule, body, tree, typeenv, termenv); From ad20e6edd86666cfee415cef31cbed7610b01f8b Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Sat, 30 Dec 2023 08:05:30 -0500 Subject: [PATCH 26/73] isle: printer skeleton --- Cargo.lock | 26 ++++++++++++ cranelift/isle/isle/Cargo.toml | 3 ++ cranelift/isle/isle/src/bin/isleprint.rs | 28 ++++++++++++ cranelift/isle/isle/src/lib.rs | 1 + cranelift/isle/isle/src/printer.rs | 54 ++++++++++++++++++++++++ 5 files changed, 112 insertions(+) create mode 100644 cranelift/isle/isle/src/bin/isleprint.rs create mode 100644 cranelift/isle/isle/src/printer.rs diff --git a/Cargo.lock b/Cargo.lock index 772bee2f6caf..7ad72a3b0f5f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -123,6 +123,12 @@ dependencies = [ "derive_arbitrary", ] +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + [[package]] name = "ascii-canvas" version = "3.0.0" @@ -788,8 +794,11 @@ dependencies = [ name = "cranelift-isle" version = "0.101.0" dependencies = [ + "clap 4.4.6", "codespan-reporting", + "env_logger 0.10.0", "log", + "pretty", "tempfile", ] @@ -2472,6 +2481,17 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" +[[package]] +name = "pretty" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55c4d17d994b637e2f4daf6e5dc5d660d209d5642377d675d7a1c3ab69fa579" +dependencies = [ + "arrayvec", + "typed-arena", + "unicode-width", +] + [[package]] name = "pretty_env_logger" version = "0.4.0" @@ -3480,6 +3500,12 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +[[package]] +name = "typed-arena" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" + [[package]] name = "typenum" version = "1.17.0" diff --git a/cranelift/isle/isle/Cargo.toml b/cranelift/isle/isle/Cargo.toml index db802bf0f06d..17b317291caf 100644 --- a/cranelift/isle/isle/Cargo.toml +++ b/cranelift/isle/isle/Cargo.toml @@ -11,6 +11,9 @@ version = "0.101.0" [dependencies] codespan-reporting = { version = "0.11.1", optional = true } log = { workspace = true, optional = true } +pretty = "0.12.3" +clap = { workspace = true } +env_logger = { workspace = true } [dev-dependencies] tempfile = "3" diff --git a/cranelift/isle/isle/src/bin/isleprint.rs b/cranelift/isle/isle/src/bin/isleprint.rs new file mode 100644 index 000000000000..19d42e1bbed3 --- /dev/null +++ b/cranelift/isle/isle/src/bin/isleprint.rs @@ -0,0 +1,28 @@ +use clap::Parser; +use cranelift_isle as isle; +use std::path::PathBuf; + +#[derive(Parser)] +struct Opts { + /// The input ISLE DSL source files. + #[clap(required = true)] + inputs: Vec, + + /// Line length. + #[clap(long, default_value = "78")] + width: usize, +} + +fn main() -> Result<(), isle::error::Errors> { + let _ = env_logger::try_init(); + + let opts = Opts::parse(); + + let lexer = isle::lexer::Lexer::from_files(&opts.inputs)?; + let defs = isle::parser::parse(lexer)?; + + let mut stdout = std::io::stdout(); + isle::printer::print(&defs, opts.width, &mut stdout)?; + + Ok(()) +} diff --git a/cranelift/isle/isle/src/lib.rs b/cranelift/isle/isle/src/lib.rs index 3171848a44ca..f56b90a469ee 100644 --- a/cranelift/isle/isle/src/lib.rs +++ b/cranelift/isle/isle/src/lib.rs @@ -267,6 +267,7 @@ pub mod lexer; mod log; pub mod overlap; pub mod parser; +pub mod printer; pub mod sema; pub mod serialize; pub mod trie_again; diff --git a/cranelift/isle/isle/src/printer.rs b/cranelift/isle/isle/src/printer.rs new file mode 100644 index 000000000000..7b660b8cd8ce --- /dev/null +++ b/cranelift/isle/isle/src/printer.rs @@ -0,0 +1,54 @@ +//! Printer for ISLE language. + +#![allow(missing_docs)] + +use crate::ast::*; +use crate::error::Errors; +use pretty::{Doc, RcDoc}; +use std::io::Write; + +pub fn print(defs: &Defs, width: usize, out: &mut W) -> Result<(), Errors> +where + W: ?Sized + Write, +{ + defs.to_doc() + .render(width, out) + .map_err(|e| Errors::from_io(e, "failed to print isle")) +} + +impl Defs { + fn to_doc(&self) -> RcDoc<()> { + let sep = RcDoc::hardline().append(Doc::hardline()); + RcDoc::intersperse(self.defs.iter().map(|d| d.to_doc()), sep).append(Doc::hardline()) + } +} + +impl Def { + fn to_doc(&self) -> RcDoc<()> { + match self { + Def::Type(t) => RcDoc::text("(") + .append( + RcDoc::intersperse( + vec![RcDoc::text("type"), t.name.to_doc(), t.ty.to_doc()], + Doc::line(), + ) + .nest(4) + .group(), + ) + .append(RcDoc::text(")")), + _ => RcDoc::as_string("def"), + } + } +} + +impl Ident { + fn to_doc(&self) -> RcDoc<()> { + RcDoc::text(self.0.clone()) + } +} + +impl TypeValue { + fn to_doc(&self) -> RcDoc<()> { + RcDoc::text("type_value") + } +} From d6ee519b886f0f26dcf5e8a9a37146df6db2c980 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Sat, 30 Dec 2023 08:38:28 -0500 Subject: [PATCH 27/73] isle: type printing --- cranelift/isle/isle/src/printer.rs | 53 ++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/cranelift/isle/isle/src/printer.rs b/cranelift/isle/isle/src/printer.rs index 7b660b8cd8ce..4aef1311a569 100644 --- a/cranelift/isle/isle/src/printer.rs +++ b/cranelift/isle/isle/src/printer.rs @@ -4,7 +4,7 @@ use crate::ast::*; use crate::error::Errors; -use pretty::{Doc, RcDoc}; +use pretty::{Doc, Pretty, RcAllocator, RcDoc}; use std::io::Write; pub fn print(defs: &Defs, width: usize, out: &mut W) -> Result<(), Errors> @@ -26,17 +26,8 @@ impl Defs { impl Def { fn to_doc(&self) -> RcDoc<()> { match self { - Def::Type(t) => RcDoc::text("(") - .append( - RcDoc::intersperse( - vec![RcDoc::text("type"), t.name.to_doc(), t.ty.to_doc()], - Doc::line(), - ) - .nest(4) - .group(), - ) - .append(RcDoc::text(")")), - _ => RcDoc::as_string("def"), + Def::Type(ref t) => sexp(vec![RcDoc::text("type"), t.name.to_doc(), t.ty.to_doc()]), + _ => RcDoc::as_string("TODO"), } } } @@ -49,6 +40,42 @@ impl Ident { impl TypeValue { fn to_doc(&self) -> RcDoc<()> { - RcDoc::text("type_value") + match self { + TypeValue::Primitive(ref name, _) => { + sexp(vec![RcDoc::text("primitive"), name.to_doc()]) + } + TypeValue::Enum(ref variants, _) => sexp( + Vec::from([RcDoc::text("enum")]) + .into_iter() + .chain(variants.iter().map(|v| v.to_doc())), + ), + } + } +} + +impl Variant { + fn to_doc(&self) -> RcDoc<()> { + sexp( + Vec::from([self.name.to_doc()]) + .into_iter() + .chain(self.fields.iter().map(|f| f.to_doc())), + ) + } +} + +impl Field { + fn to_doc(&self) -> RcDoc<()> { + sexp(vec![self.name.to_doc(), self.ty.to_doc()]) } } + +fn sexp<'a, I, A>(docs: I) -> RcDoc<'a, A> +where + I: IntoIterator, + I::Item: Pretty<'a, RcAllocator, A>, + A: Clone, +{ + RcDoc::text("(") + .append(RcDoc::intersperse(docs, Doc::line()).nest(4).group()) + .append(RcDoc::text(")")) +} From 8ed0d013e89d0dd74a275018129c657a2e2fdf11 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Sat, 30 Dec 2023 10:22:09 -0500 Subject: [PATCH 28/73] isle: printer supports more things --- cranelift/isle/isle/src/printer.rs | 116 ++++++++++++++++++++++++++++- 1 file changed, 115 insertions(+), 1 deletion(-) diff --git a/cranelift/isle/isle/src/printer.rs b/cranelift/isle/isle/src/printer.rs index 4aef1311a569..2b272acbab72 100644 --- a/cranelift/isle/isle/src/printer.rs +++ b/cranelift/isle/isle/src/printer.rs @@ -27,7 +27,46 @@ impl Def { fn to_doc(&self) -> RcDoc<()> { match self { Def::Type(ref t) => sexp(vec![RcDoc::text("type"), t.name.to_doc(), t.ty.to_doc()]), - _ => RcDoc::as_string("TODO"), + Def::Rule(ref r) => { + let mut parts = Vec::new(); + parts.push(RcDoc::text("rule")); + if let Some(name) = &r.name { + parts.push(name.to_doc()); + } + if let Some(prio) = &r.prio { + parts.push(RcDoc::as_string(prio)); + } + parts.push(r.pattern.to_doc()); + // TODO(mbm): if-lets + parts.push(r.expr.to_doc()); + sexp(parts) + } + // TODO: Extractor(Extractor), + Def::Decl(ref d) => { + let mut parts = Vec::new(); + parts.push(RcDoc::text("decl")); + if d.pure { + parts.push(RcDoc::text("pure")); + } + if d.multi { + parts.push(RcDoc::text("multi")); + } + if d.partial { + parts.push(RcDoc::text("partial")); + } + parts.push(d.term.to_doc()); + parts.push(sexp(d.arg_tys.iter().map(|ty| ty.to_doc()))); + parts.push(d.ret_ty.to_doc()); + sexp(parts) + } + // TODO: Spec(Spec), + // TODO: Model(Model), + // TODO: Form(Form), + // TODO: Instantiation(Instantiation), + // TODO: Extern(Extern), + Def::Extern(ref e) => e.to_doc(), + // TODO: Converter(Converter), + _ => todo!("def: {:?}", self), } } } @@ -45,6 +84,7 @@ impl TypeValue { sexp(vec![RcDoc::text("primitive"), name.to_doc()]) } TypeValue::Enum(ref variants, _) => sexp( + // TODO(mbm): convenience for sexp with a fixed first element Vec::from([RcDoc::text("enum")]) .into_iter() .chain(variants.iter().map(|v| v.to_doc())), @@ -56,6 +96,7 @@ impl TypeValue { impl Variant { fn to_doc(&self) -> RcDoc<()> { sexp( + // TODO(mbm): convenience for sexp with a fixed first element Vec::from([self.name.to_doc()]) .into_iter() .chain(self.fields.iter().map(|f| f.to_doc())), @@ -69,6 +110,79 @@ impl Field { } } +impl Pattern { + fn to_doc(&self) -> RcDoc<()> { + match self { + Pattern::Var { var, .. } => var.to_doc(), + Pattern::BindPattern { var, subpat, .. } => RcDoc::intersperse( + vec![var.to_doc(), RcDoc::text("@"), subpat.to_doc()], + Doc::space(), + ), + Pattern::ConstInt { val, .. } => RcDoc::as_string(val), + Pattern::ConstPrim { val, .. } => val.to_doc(), + Pattern::Wildcard { .. } => RcDoc::text("_"), + Pattern::Term { sym, args, .. } => sexp( + // TODO(mbm): convenience for sexp with a fixed first element + Vec::from([sym.to_doc()]) + .into_iter() + .chain(args.iter().map(|f| f.to_doc())), + ), + _ => todo!("pattern: {:?}", self), + } + } +} + +impl Expr { + fn to_doc(&self) -> RcDoc<()> { + match self { + Expr::Term { sym, args, .. } => sexp( + // TODO(mbm): convenience for sexp with a fixed first element + Vec::from([sym.to_doc()]) + .into_iter() + .chain(args.iter().map(|f| f.to_doc())), + ), + Expr::Var { name, .. } => name.to_doc(), + Expr::ConstInt { val, .. } => RcDoc::as_string(val), + Expr::ConstPrim { val, .. } => val.to_doc(), + Expr::Let { defs, body, .. } => { + let mut parts = Vec::new(); + parts.push(RcDoc::text("let")); + parts.extend(defs.iter().map(|d| d.to_doc())); + parts.push(body.to_doc()); + sexp(parts) + } + } + } +} + +impl LetDef { + fn to_doc(&self) -> RcDoc<()> { + sexp(vec![self.var.to_doc(), self.ty.to_doc(), self.val.to_doc()]) + } +} + +impl Extern { + fn to_doc(&self) -> RcDoc<()> { + match self { + Extern::Extractor { + term, + func, + pos: _, + infallible, + } => { + let mut parts = vec![RcDoc::text("extern"), RcDoc::text("extractor")]; + if *infallible { + parts.push(RcDoc::text("infallible")); + } + parts.push(term.to_doc()); + parts.push(func.to_doc()); + sexp(parts) + } + _ => todo!("extern: {:?}", self), + } + } +} + fn sexp<'a, I, A>(docs: I) -> RcDoc<'a, A> where I: IntoIterator, From 81e1fb63b66741720a640e3765c24f2576ba0aa0 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Sat, 30 Dec 2023 11:07:20 -0500 Subject: [PATCH 29/73] isle: more printing --- cranelift/isle/isle/src/printer.rs | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/cranelift/isle/isle/src/printer.rs b/cranelift/isle/isle/src/printer.rs index 2b272acbab72..6f3ccab98b43 100644 --- a/cranelift/isle/isle/src/printer.rs +++ b/cranelift/isle/isle/src/printer.rs @@ -41,7 +41,15 @@ impl Def { parts.push(r.expr.to_doc()); sexp(parts) } - // TODO: Extractor(Extractor), + Def::Extractor(ref e) => sexp(vec![ + RcDoc::text("extractor"), + sexp( + Vec::from([e.term.to_doc()]) + .into_iter() + .chain(e.args.iter().map(|v| v.to_doc())), + ), + e.template.to_doc(), + ]), Def::Decl(ref d) => { let mut parts = Vec::new(); parts.push(RcDoc::text("decl")); @@ -65,7 +73,12 @@ impl Def { // TODO: Instantiation(Instantiation), // TODO: Extern(Extern), Def::Extern(ref e) => e.to_doc(), - // TODO: Converter(Converter), + Def::Converter(ref c) => sexp(vec![ + RcDoc::text("convert"), + c.inner_ty.to_doc(), + c.outer_ty.to_doc(), + c.term.to_doc(), + ]), _ => todo!("def: {:?}", self), } } @@ -178,6 +191,12 @@ impl Extern { parts.push(func.to_doc()); sexp(parts) } + Extern::Constructor { term, func, .. } => sexp(vec![ + RcDoc::text("extern"), + RcDoc::text("constructor"), + term.to_doc(), + func.to_doc(), + ]), _ => todo!("extern: {:?}", self), } } From f491dfb58f65c3a2b1e0d6f26a36a4a1c8fd5f90 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Sat, 30 Dec 2023 11:41:41 -0500 Subject: [PATCH 30/73] isle: more spec printing --- .../isle/isle_examples/pass/veri_spec.isle | 10 +-- cranelift/isle/isle/src/printer.rs | 82 +++++++++++++++++-- 2 files changed, 82 insertions(+), 10 deletions(-) diff --git a/cranelift/isle/isle/isle_examples/pass/veri_spec.isle b/cranelift/isle/isle/isle_examples/pass/veri_spec.isle index d9b4cfe16059..886f1ffcf81d 100644 --- a/cranelift/isle/isle/isle_examples/pass/veri_spec.isle +++ b/cranelift/isle/isle/isle_examples/pass/veri_spec.isle @@ -2,14 +2,14 @@ (form unary_bv_8_to_64 - (args ((bv 8)) (return (bv 8)) (canon (bv 8))) - (args ((bv 16)) (return (bv 16)) (canon (bv 16))) - (args ((bv 32)) (return (bv 32)) (canon (bv 32))) - (args ((bv 64)) (return (bv 64)) (canon (bv 64))) + ((args (bv 8)) (ret (bv 8)) (canon (bv 8))) + ((args (bv 16)) (ret (bv 16)) (canon (bv 16))) + ((args (bv 32)) (ret (bv 32)) (canon (bv 32))) + ((args (bv 64)) (ret (bv 64)) (canon (bv 64))) ) (spec (A i j) (provide (= (if true (= i j) (= i (bvneg j)))))) -(instantiate A (args ((bv 8)) (return (bv 8)) (canon (bv 8)))) +(instantiate A ((args (bv 8)) (ret (bv 8)) (canon (bv 8)))) (decl A (u8 u8) u8) (spec (B i) diff --git a/cranelift/isle/isle/src/printer.rs b/cranelift/isle/isle/src/printer.rs index 6f3ccab98b43..d7e886030b0f 100644 --- a/cranelift/isle/isle/src/printer.rs +++ b/cranelift/isle/isle/src/printer.rs @@ -67,11 +67,31 @@ impl Def { parts.push(d.ret_ty.to_doc()); sexp(parts) } - // TODO: Spec(Spec), - // TODO: Model(Model), - // TODO: Form(Form), - // TODO: Instantiation(Instantiation), - // TODO: Extern(Extern), + Def::Spec(ref s) => { + let mut parts = vec![RcDoc::text("spec")]; + parts.push(sexp( + Vec::from([s.term.to_doc()]) + .into_iter() + .chain(s.args.iter().map(|v| v.to_doc())), + )); + sexp(parts) + } + Def::Model(ref m) => sexp(vec![RcDoc::text("model"), m.name.to_doc(), m.val.to_doc()]), + Def::Form(ref f) => { + let mut parts = vec![RcDoc::text("form")]; + parts.push(f.name.to_doc()); + parts.extend(f.signatures.iter().map(|s| s.to_doc())); + sexp(parts) + } + Def::Instantiation(ref i) => { + let mut parts = vec![RcDoc::text("instatiate"), i.term.to_doc()]; + if let Some(form) = &i.form { + parts.push(form.to_doc()); + } else { + parts.extend(i.signatures.iter().map(|s| s.to_doc())); + } + sexp(parts) + } Def::Extern(ref e) => e.to_doc(), Def::Converter(ref c) => sexp(vec![ RcDoc::text("convert"), @@ -123,6 +143,58 @@ impl Field { } } +impl ModelValue { + fn to_doc(&self) -> RcDoc<()> { + match self { + ModelValue::TypeValue(ref mt) => sexp(vec![RcDoc::text("type"), mt.to_doc()]), + ModelValue::EnumValues(ref values) => sexp( + Vec::from([RcDoc::text("enum")]).into_iter().chain( + values + .iter() + .map(|(name, expr)| sexp(vec![name.to_doc(), expr.to_doc()])), + ), + ), + } + } +} + +impl ModelType { + fn to_doc(&self) -> RcDoc<()> { + match self { + ModelType::BitVec(Some(size)) => sexp(vec![RcDoc::text("bv"), RcDoc::as_string(size)]), + _ => todo!("model type: {:?}", self), + } + } +} + +impl Signature { + fn to_doc(&self) -> RcDoc<()> { + sexp(vec![ + sexp( + Vec::from([RcDoc::text("args")]) + .into_iter() + .chain(self.args.iter().map(|a| a.to_doc())), + ), + sexp(vec![RcDoc::text("ret"), self.ret.to_doc()]), + sexp(vec![RcDoc::text("canon"), self.canonical.to_doc()]), + ]) + } +} + +impl SpecExpr { + fn to_doc(&self) -> RcDoc<()> { + match self { + SpecExpr::ConstInt { val, .. } => RcDoc::as_string(val), + SpecExpr::ConstBitVec { val, width, .. } => RcDoc::text(if width % 4 == 0 { + format!("#x{val:width$x}", width = *width as usize / 4) + } else { + format!("#b{val:width$b}", width = *width as usize) + }), + _ => todo!("spec expr: {:?}", self), + } + } +} + impl Pattern { fn to_doc(&self) -> RcDoc<()> { match self { From 1ff75fcd646fa3d8d5de1185a9dce8eebf02defb Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Sat, 30 Dec 2023 12:24:56 -0500 Subject: [PATCH 31/73] isle: more printing --- cranelift/isle/isle/src/printer.rs | 101 +++++++++++++++++++++++++++-- 1 file changed, 94 insertions(+), 7 deletions(-) diff --git a/cranelift/isle/isle/src/printer.rs b/cranelift/isle/isle/src/printer.rs index d7e886030b0f..bc5c04c1ec9f 100644 --- a/cranelift/isle/isle/src/printer.rs +++ b/cranelift/isle/isle/src/printer.rs @@ -26,6 +26,7 @@ impl Defs { impl Def { fn to_doc(&self) -> RcDoc<()> { match self { + Def::Pragma(_) => unimplemented!("pragmas not supported"), Def::Type(ref t) => sexp(vec![RcDoc::text("type"), t.name.to_doc(), t.ty.to_doc()]), Def::Rule(ref r) => { let mut parts = Vec::new(); @@ -72,8 +73,22 @@ impl Def { parts.push(sexp( Vec::from([s.term.to_doc()]) .into_iter() - .chain(s.args.iter().map(|v| v.to_doc())), + .chain(s.args.iter().map(|a| a.to_doc())), )); + if !s.provides.is_empty() { + parts.push(sexp( + Vec::from([RcDoc::text("provide")]) + .into_iter() + .chain(s.provides.iter().map(|e| e.to_doc())), + )); + } + if !s.requires.is_empty() { + parts.push(sexp( + Vec::from([RcDoc::text("require")]) + .into_iter() + .chain(s.requires.iter().map(|e| e.to_doc())), + )); + } sexp(parts) } Def::Model(ref m) => sexp(vec![RcDoc::text("model"), m.name.to_doc(), m.val.to_doc()]), @@ -99,7 +114,6 @@ impl Def { c.outer_ty.to_doc(), c.term.to_doc(), ]), - _ => todo!("def: {:?}", self), } } } @@ -161,8 +175,10 @@ impl ModelValue { impl ModelType { fn to_doc(&self) -> RcDoc<()> { match self { + ModelType::Int => RcDoc::text("Int"), + ModelType::Bool => RcDoc::text("Bool"), ModelType::BitVec(Some(size)) => sexp(vec![RcDoc::text("bv"), RcDoc::as_string(size)]), - _ => todo!("model type: {:?}", self), + ModelType::BitVec(None) => sexp(vec![RcDoc::text("bv")]), } } } @@ -186,15 +202,81 @@ impl SpecExpr { match self { SpecExpr::ConstInt { val, .. } => RcDoc::as_string(val), SpecExpr::ConstBitVec { val, width, .. } => RcDoc::text(if width % 4 == 0 { - format!("#x{val:width$x}", width = *width as usize / 4) + format!("#x{val:0width$x}", width = *width as usize / 4) } else { - format!("#b{val:width$b}", width = *width as usize) + format!("#b{val:0width$b}", width = *width as usize) }), - _ => todo!("spec expr: {:?}", self), + SpecExpr::ConstBool { val, .. } => { + RcDoc::text(if *val != 0 { "true" } else { "false" }) + } + SpecExpr::Var { var, .. } => var.to_doc(), + SpecExpr::Op { op, args, .. } => sexp( + Vec::from([op.to_doc()]) + .into_iter() + .chain(args.iter().map(|a| a.to_doc())), + ), + SpecExpr::Pair { l, r } => sexp(vec![l.to_doc(), r.to_doc()]), + SpecExpr::Enum { name } => sexp(vec![name.to_doc()]), } } } +impl SpecOp { + fn to_doc(&self) -> RcDoc<()> { + RcDoc::text(match self { + SpecOp::Eq => "=", + SpecOp::And => "and", + SpecOp::Not => "not", + SpecOp::Or => "or", + SpecOp::Lte => "<=", + SpecOp::Lt => "<", + SpecOp::Gte => ">=", + SpecOp::Gt => ">", + SpecOp::BVNot => "bvnot", + SpecOp::BVAnd => "bvand", + SpecOp::BVOr => "bvor", + SpecOp::BVXor => "bvxor", + SpecOp::BVNeg => "bvneg", + SpecOp::BVAdd => "bvadd", + SpecOp::BVSub => "bvsub", + SpecOp::BVMul => "bvmul", + SpecOp::BVUdiv => "bvudiv", + SpecOp::BVUrem => "bvurem", + SpecOp::BVSdiv => "bvsdiv", + SpecOp::BVSrem => "bvsrem", + SpecOp::BVShl => "bvshl", + SpecOp::BVLshr => "bvlshr", + SpecOp::BVAshr => "bvashr", + SpecOp::BVSaddo => "bvsaddo", + SpecOp::BVUle => "bvule", + SpecOp::BVUlt => "bvult", + SpecOp::BVUgt => "bvugt", + SpecOp::BVUge => "bvuge", + SpecOp::BVSlt => "bvslt", + SpecOp::BVSle => "bvsle", + SpecOp::BVSgt => "bvsgt", + SpecOp::BVSge => "bvsge", + SpecOp::Rotr => "rotr", + SpecOp::Rotl => "rotl", + SpecOp::Extract => "extract", + SpecOp::ZeroExt => "zero_ext", + SpecOp::SignExt => "sign_ext", + SpecOp::Concat => "concat", + SpecOp::ConvTo => "conv_to", + SpecOp::Int2BV => "int2bv", + SpecOp::BV2Int => "bv2int", + SpecOp::WidthOf => "widthof", + SpecOp::If => "if", + SpecOp::Switch => "switch", + SpecOp::Subs => "subs", + SpecOp::Popcnt => "popcnt", + SpecOp::Rev => "rev", + SpecOp::Cls => "cls", + SpecOp::Clz => "clz", + }) + } +} + impl Pattern { fn to_doc(&self) -> RcDoc<()> { match self { @@ -212,7 +294,12 @@ impl Pattern { .into_iter() .chain(args.iter().map(|f| f.to_doc())), ), - _ => todo!("pattern: {:?}", self), + Pattern::And { subpats, .. } => sexp( + Vec::from([RcDoc::text("and")]) + .into_iter() + .chain(subpats.iter().map(|p| p.to_doc())), + ), + Pattern::MacroArg { .. } => unimplemented!("macro arguments are for internal use only"), } } } From ba0a01afcb24f17b7774f61cc27df259988232e9 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Sat, 30 Dec 2023 13:56:39 -0500 Subject: [PATCH 32/73] isle: print if-let --- cranelift/isle/isle/src/printer.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/cranelift/isle/isle/src/printer.rs b/cranelift/isle/isle/src/printer.rs index bc5c04c1ec9f..5ff1f9cade69 100644 --- a/cranelift/isle/isle/src/printer.rs +++ b/cranelift/isle/isle/src/printer.rs @@ -38,7 +38,7 @@ impl Def { parts.push(RcDoc::as_string(prio)); } parts.push(r.pattern.to_doc()); - // TODO(mbm): if-lets + parts.extend(r.iflets.iter().map(|il| il.to_doc())); parts.push(r.expr.to_doc()); sexp(parts) } @@ -304,6 +304,17 @@ impl Pattern { } } +impl IfLet { + fn to_doc(&self) -> RcDoc<()> { + // TODO(mbm): `if` shorthand when pattern is wildcard + sexp(vec![ + RcDoc::text("if-let"), + self.pattern.to_doc(), + self.expr.to_doc(), + ]) + } +} + impl Expr { fn to_doc(&self) -> RcDoc<()> { match self { From df71a75a565aa168d1cd068c2442ab47852c7138 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Sat, 30 Dec 2023 14:18:52 -0500 Subject: [PATCH 33/73] basic printer tests --- cranelift/isle/isle/build.rs | 1 + cranelift/isle/isle/src/printer.rs | 7 ++++++- cranelift/isle/isle/tests/run_tests.rs | 14 ++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/cranelift/isle/isle/build.rs b/cranelift/isle/isle/build.rs index 96aa9ec06d44..d522564464bc 100644 --- a/cranelift/isle/isle/build.rs +++ b/cranelift/isle/isle/build.rs @@ -14,6 +14,7 @@ fn main() { emit_tests(&mut out, "isle_examples/fail", "run_fail"); emit_tests(&mut out, "isle_examples/link", "run_link"); emit_tests(&mut out, "isle_examples/run", "run_run"); + emit_tests(&mut out, "isle_examples/pass", "run_print"); let output = out_dir.join("isle_tests.rs"); std::fs::write(output, out).unwrap(); diff --git a/cranelift/isle/isle/src/printer.rs b/cranelift/isle/isle/src/printer.rs index 5ff1f9cade69..3cf49aa40031 100644 --- a/cranelift/isle/isle/src/printer.rs +++ b/cranelift/isle/isle/src/printer.rs @@ -367,7 +367,12 @@ impl Extern { term.to_doc(), func.to_doc(), ]), - _ => todo!("extern: {:?}", self), + Extern::Const { name, ty, .. } => sexp(vec![ + RcDoc::text("extern"), + RcDoc::text("const"), + name.to_doc(), + ty.to_doc(), + ]), } } } diff --git a/cranelift/isle/isle/tests/run_tests.rs b/cranelift/isle/isle/tests/run_tests.rs index 1b347b9454ce..5af541f822b0 100644 --- a/cranelift/isle/isle/tests/run_tests.rs +++ b/cranelift/isle/isle/tests/run_tests.rs @@ -2,7 +2,11 @@ use cranelift_isle::compile; use cranelift_isle::error::Errors; +use cranelift_isle::lexer; +use cranelift_isle::parser; +use cranelift_isle::printer; use std::default::Default; +use std::io::BufWriter; fn build(filename: &str) -> Result { compile::from_files(&[filename], &Default::default()) @@ -63,6 +67,16 @@ pub fn run_link(isle_filename: &str) { build_and_link_isle(isle_filename); } +pub fn run_print(isle_filename: &str) { + // Parse. + let lexer = lexer::Lexer::from_files(&[isle_filename]).unwrap(); + let defs = parser::parse(lexer).unwrap(); + + // Print. + let mut buf = BufWriter::new(Vec::new()); + printer::print(&defs, 78, &mut buf).unwrap(); +} + pub fn run_run(isle_filename: &str) { let (_tempdir, exe) = build_and_link_isle(isle_filename); From 1e70a2fbb648277a9622c056fd06c6a03b2c3a32 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Sat, 30 Dec 2023 14:29:26 -0500 Subject: [PATCH 34/73] ensure printed isle parses --- cranelift/isle/isle/src/printer.rs | 6 +++--- cranelift/isle/isle/tests/run_tests.rs | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/cranelift/isle/isle/src/printer.rs b/cranelift/isle/isle/src/printer.rs index 3cf49aa40031..0b8070522c33 100644 --- a/cranelift/isle/isle/src/printer.rs +++ b/cranelift/isle/isle/src/printer.rs @@ -99,7 +99,7 @@ impl Def { sexp(parts) } Def::Instantiation(ref i) => { - let mut parts = vec![RcDoc::text("instatiate"), i.term.to_doc()]; + let mut parts = vec![RcDoc::text("instantiate"), i.term.to_doc()]; if let Some(form) = &i.form { parts.push(form.to_doc()); } else { @@ -330,7 +330,7 @@ impl Expr { Expr::Let { defs, body, .. } => { let mut parts = Vec::new(); parts.push(RcDoc::text("let")); - parts.extend(defs.iter().map(|d| d.to_doc())); + parts.push(sexp(defs.iter().map(|d| d.to_doc()))); parts.push(body.to_doc()); sexp(parts) } @@ -370,7 +370,7 @@ impl Extern { Extern::Const { name, ty, .. } => sexp(vec![ RcDoc::text("extern"), RcDoc::text("const"), - name.to_doc(), + RcDoc::text(format!("${}", name.0)), ty.to_doc(), ]), } diff --git a/cranelift/isle/isle/tests/run_tests.rs b/cranelift/isle/isle/tests/run_tests.rs index 5af541f822b0..91482ee680ec 100644 --- a/cranelift/isle/isle/tests/run_tests.rs +++ b/cranelift/isle/isle/tests/run_tests.rs @@ -75,6 +75,12 @@ pub fn run_print(isle_filename: &str) { // Print. let mut buf = BufWriter::new(Vec::new()); printer::print(&defs, 78, &mut buf).unwrap(); + let bytes = buf.into_inner().unwrap(); + let isle_source = String::from_utf8(bytes).unwrap(); + + // Round trip. + let lexer = lexer::Lexer::from_str(&isle_source, "").unwrap(); + let _round_trip = parser::parse(lexer).unwrap(); } pub fn run_run(isle_filename: &str) { From 2876e90f9d6e3ea4f408375124ec690614cbb5c9 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Sat, 30 Dec 2023 15:43:40 -0500 Subject: [PATCH 35/73] alow position tagging to be disabled --- cranelift/isle/isle/src/parser.rs | 29 ++++++++++++++++++++------ cranelift/isle/isle/tests/run_tests.rs | 24 ++++++++++++++++----- 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/cranelift/isle/isle/src/parser.rs b/cranelift/isle/isle/src/parser.rs index 1f3978bf7cf4..174b02439880 100644 --- a/cranelift/isle/isle/src/parser.rs +++ b/cranelift/isle/isle/src/parser.rs @@ -1,5 +1,7 @@ //! Parser for ISLE language. +#![allow(missing_docs)] + use crate::ast::*; use crate::error::{Error, Errors, Span}; use crate::lexer::{Lexer, Pos, Token}; @@ -16,8 +18,11 @@ pub fn parse(lexer: Lexer) -> Result { /// /// Takes in a lexer and creates an AST. #[derive(Clone, Debug)] -struct Parser<'a> { +pub struct Parser<'a> { lexer: Lexer<'a>, + + // HACK: allow positions to be disabled to support testing + populate_pos: bool, } /// Used during parsing a `(rule ...)` to encapsulate some form that @@ -31,7 +36,15 @@ enum IfLetOrExpr { impl<'a> Parser<'a> { /// Construct a new parser from the given lexer. pub fn new(lexer: Lexer<'a>) -> Parser<'a> { - Parser { lexer } + Parser { + lexer, + populate_pos: true, + } + } + + // HACK: allow positions to be disabled to support testing + pub fn disable_pos(&mut self) { + self.populate_pos = false; } fn error(&self, pos: Pos, msg: String) -> Errors { @@ -76,9 +89,13 @@ impl<'a> Parser<'a> { } fn pos(&self) -> Pos { - self.lexer - .peek() - .map_or_else(|| self.lexer.pos(), |(pos, _)| *pos) + if self.populate_pos { + self.lexer + .peek() + .map_or_else(|| self.lexer.pos(), |(pos, _)| *pos) + } else { + Pos::default() + } } fn is_lparen(&self) -> bool { @@ -150,7 +167,7 @@ impl<'a> Parser<'a> { } } - fn parse_defs(mut self) -> Result { + pub fn parse_defs(mut self) -> Result { let mut defs = vec![]; while !self.lexer.eof() { defs.push(self.parse_def()?); diff --git a/cranelift/isle/isle/tests/run_tests.rs b/cranelift/isle/isle/tests/run_tests.rs index 91482ee680ec..2c25b8f1f133 100644 --- a/cranelift/isle/isle/tests/run_tests.rs +++ b/cranelift/isle/isle/tests/run_tests.rs @@ -1,12 +1,20 @@ //! Helper for autogenerated unit tests. +use cranelift_isle::ast::Defs; use cranelift_isle::compile; use cranelift_isle::error::Errors; -use cranelift_isle::lexer; -use cranelift_isle::parser; +use cranelift_isle::lexer::{self, Lexer}; +use cranelift_isle::parser::Parser; use cranelift_isle::printer; use std::default::Default; use std::io::BufWriter; +use std::iter::zip; + +fn parse(lexer: Lexer) -> Result { + let mut parser = Parser::new(lexer); + parser.disable_pos(); + parser.parse_defs() +} fn build(filename: &str) -> Result { compile::from_files(&[filename], &Default::default()) @@ -70,17 +78,23 @@ pub fn run_link(isle_filename: &str) { pub fn run_print(isle_filename: &str) { // Parse. let lexer = lexer::Lexer::from_files(&[isle_filename]).unwrap(); - let defs = parser::parse(lexer).unwrap(); + let original = parse(lexer).unwrap(); // Print. let mut buf = BufWriter::new(Vec::new()); - printer::print(&defs, 78, &mut buf).unwrap(); + printer::print(&original, 78, &mut buf).unwrap(); let bytes = buf.into_inner().unwrap(); let isle_source = String::from_utf8(bytes).unwrap(); // Round trip. let lexer = lexer::Lexer::from_str(&isle_source, "").unwrap(); - let _round_trip = parser::parse(lexer).unwrap(); + let round_trip = parse(lexer).unwrap(); + + // Ensure equal. + assert_eq!(original.defs.len(), round_trip.defs.len()); + for (orig, rt) in zip(original.defs, round_trip.defs) { + assert_eq!(orig, rt); + } } pub fn run_run(isle_filename: &str) { From cda22d8afd40b8a11a735c667868dca049cdff92 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Sat, 30 Dec 2023 17:54:47 -0500 Subject: [PATCH 36/73] fix roundtrip errors --- cranelift/isle/isle/src/printer.rs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/cranelift/isle/isle/src/printer.rs b/cranelift/isle/isle/src/printer.rs index 0b8070522c33..19608d081b9d 100644 --- a/cranelift/isle/isle/src/printer.rs +++ b/cranelift/isle/isle/src/printer.rs @@ -27,7 +27,18 @@ impl Def { fn to_doc(&self) -> RcDoc<()> { match self { Def::Pragma(_) => unimplemented!("pragmas not supported"), - Def::Type(ref t) => sexp(vec![RcDoc::text("type"), t.name.to_doc(), t.ty.to_doc()]), + Def::Type(ref t) => { + let mut parts = vec![RcDoc::text("type")]; + parts.push(t.name.to_doc()); + if t.is_extern { + parts.push(RcDoc::text("extern")); + } + if t.is_nodebug { + parts.push(RcDoc::text("nodebug")); + } + parts.push(t.ty.to_doc()); + sexp(parts) + } Def::Rule(ref r) => { let mut parts = Vec::new(); parts.push(RcDoc::text("rule")); @@ -286,7 +297,7 @@ impl Pattern { Doc::space(), ), Pattern::ConstInt { val, .. } => RcDoc::as_string(val), - Pattern::ConstPrim { val, .. } => val.to_doc(), + Pattern::ConstPrim { val, .. } => RcDoc::text("$").append(val.to_doc()), Pattern::Wildcard { .. } => RcDoc::text("_"), Pattern::Term { sym, args, .. } => sexp( // TODO(mbm): convenience for sexp with a fixed first element @@ -326,7 +337,7 @@ impl Expr { ), Expr::Var { name, .. } => name.to_doc(), Expr::ConstInt { val, .. } => RcDoc::as_string(val), - Expr::ConstPrim { val, .. } => val.to_doc(), + Expr::ConstPrim { val, .. } => RcDoc::text("$").append(val.to_doc()), Expr::Let { defs, body, .. } => { let mut parts = Vec::new(); parts.push(RcDoc::text("let")); @@ -370,7 +381,7 @@ impl Extern { Extern::Const { name, ty, .. } => sexp(vec![ RcDoc::text("extern"), RcDoc::text("const"), - RcDoc::text(format!("${}", name.0)), + RcDoc::text("$").append(name.to_doc()), ty.to_doc(), ]), } From dc155ce6340984e41a81f456e3e9c366b93ee728 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Sat, 30 Dec 2023 18:40:23 -0500 Subject: [PATCH 37/73] test against full isle files --- cranelift/isle/isle/build.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/cranelift/isle/isle/build.rs b/cranelift/isle/isle/build.rs index d522564464bc..191c4b0e63e1 100644 --- a/cranelift/isle/isle/build.rs +++ b/cranelift/isle/isle/build.rs @@ -1,4 +1,4 @@ -use std::fmt::Write; +use std::{fmt::Write, path::PathBuf}; fn main() { println!("cargo:rerun-if-changed=build.rs"); @@ -14,14 +14,21 @@ fn main() { emit_tests(&mut out, "isle_examples/fail", "run_fail"); emit_tests(&mut out, "isle_examples/link", "run_link"); emit_tests(&mut out, "isle_examples/run", "run_run"); + emit_tests(&mut out, "isle_examples/pass", "run_print"); + emit_tests(&mut out, "../../codegen/src/opts", "run_print"); + emit_tests(&mut out, "../../codegen/src/isa/x64", "run_print"); + emit_tests(&mut out, "../../codegen/src/isa/aarch64", "run_print"); + emit_tests(&mut out, "../../codegen/src/isa/riscv64", "run_print"); let output = out_dir.join("isle_tests.rs"); std::fs::write(output, out).unwrap(); } fn emit_tests(out: &mut String, dir_name: &str, runner_func: &str) { - for test_file in std::fs::read_dir(dir_name).unwrap() { + let dir_path = PathBuf::from(dir_name); + let test_name = dir_path.file_name().unwrap().to_string_lossy(); + for test_file in std::fs::read_dir(&dir_path).unwrap() { let test_file = test_file.unwrap().file_name().into_string().unwrap(); if !test_file.ends_with(".isle") { continue; @@ -29,7 +36,12 @@ fn emit_tests(out: &mut String, dir_name: &str, runner_func: &str) { let test_file_base = test_file.replace(".isle", ""); writeln!(out, "#[test]").unwrap(); - writeln!(out, "fn test_{}_{}() {{", runner_func, test_file_base).unwrap(); + writeln!( + out, + "fn test_{}_{}_{}() {{", + runner_func, test_name, test_file_base + ) + .unwrap(); writeln!(out, " {}(\"{}/{}\");", runner_func, dir_name, test_file).unwrap(); writeln!(out, "}}").unwrap(); } From 227989e15337fedcc07daebc2fc39e64fd7bfdd1 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Mon, 1 Jan 2024 11:48:59 -0500 Subject: [PATCH 38/73] start trace to spec translation --- cranelift/isle/veri/veri_engine/src/emit.rs | 145 +++++++++++++++++++- 1 file changed, 144 insertions(+), 1 deletion(-) diff --git a/cranelift/isle/veri/veri_engine/src/emit.rs b/cranelift/isle/veri/veri_engine/src/emit.rs index 652f2c6c0156..6c87e9b851eb 100644 --- a/cranelift/isle/veri/veri_engine/src/emit.rs +++ b/cranelift/isle/veri/veri_engine/src/emit.rs @@ -4,6 +4,9 @@ use cranelift_codegen::settings; use cranelift_codegen::AllocationConsumer; use cranelift_codegen::MachBuffer; use cranelift_codegen::MachInstEmit; +use cranelift_isle::ast::Ident; +use cranelift_isle::ast::{SpecExpr, SpecOp}; +use cranelift_isle::lexer::Pos; use crossbeam::queue::SegQueue; use isla::opts; use isla_lib::bitvector::{b64::B64, BV}; @@ -155,6 +158,7 @@ fn main() -> anyhow::Result<()> { println!("inst = {inst:?}"); println!("opcode = {opcode:08x}"); println!("asm = {asm}"); + println!(""); // ISLA trace. let paths = trace_opcode(opcode, &iarch)?; @@ -167,8 +171,13 @@ fn main() -> anyhow::Result<()> { } else { events }; - println!(""); write_events(&events, &iarch)?; + + // Generate spec. + let spec = trace_to_spec(&events); + println!("spec = {spec:?}"); + + println!(""); } } @@ -507,3 +516,137 @@ fn write_events<'ir, B: BV>( Ok(()) } + +struct TypeContext { + ty: HashMap, + fun: HashMap, smtlib::Ty)>, +} + +impl TypeContext { + fn new() -> TypeContext { + TypeContext { + ty: HashMap::new(), + fun: HashMap::new(), + } + } + + fn infer(&self, exp: &smtlib::Exp) -> Option { + exp.infer(&self.ty, &self.fun) + } +} + +fn trace_to_spec(events: &Vec>) -> Vec { + let mut tctx = TypeContext::new(); + events + .iter() + .filter_map(|e| event_to_spec(e, &mut tctx)) + .collect() +} + +fn event_to_spec(event: &Event, tctx: &mut TypeContext) -> Option { + match event { + Event::Smt(def, attr, ..) if !attr.is_uninteresting() => smt_to_spec(def, tctx), + _ => None, + } +} + +fn smt_to_spec(def: &smtlib::Def, tctx: &mut TypeContext) -> Option { + match def { + smtlib::Def::DefineConst(sym, exp) => Some(SpecExpr::Op { + op: SpecOp::Eq, + args: vec![ + exp_to_spec(&smtlib::Exp::Var(*sym), tctx), + exp_to_spec(exp, tctx), + ], + pos: Pos::default(), + }), + + smtlib::Def::DeclareConst(v, ty) => { + tctx.ty.insert(*v, ty.clone()); + None + } + + smtlib::Def::DeclareFun(v, params, ret) => { + tctx.fun.insert(*v, (params.clone(), ret.clone())); + None + } + + smtlib::Def::DefineEnum(..) => None, + + _ => todo!("smt def: {:?}", def), + } +} + +fn exp_to_spec(exp: &smtlib::Exp, tctx: &TypeContext) -> SpecExpr { + use smtlib::Exp::*; + match exp { + Var(v) => SpecExpr::Var { + var: Ident(format!("v{}", v), Pos::default()), + pos: Pos::default(), + }, + + // Bits(Vec), + // Bits64(B64), + // Enum(EnumMember), + // Bool(bool), + // Eq(Box>, Box>), + // Neq(Box>, Box>), + // And(Box>, Box>), + // Or(Box>, Box>), + // Not(Box>), + // Bvnot(Box>), + // Bvand(Box>, Box>), + // Bvor(Box>, Box>), + // Bvxor(Box>, Box>), + // Bvnand(Box>, Box>), + // Bvnor(Box>, Box>), + // Bvxnor(Box>, Box>), + // Bvneg(Box>), + // Bvadd(Box>, Box>), + // Bvsub(Box>, Box>), + // Bvmul(Box>, Box>), + // Bvudiv(Box>, Box>), + // Bvsdiv(Box>, Box>), + // Bvurem(Box>, Box>), + // Bvsrem(Box>, Box>), + // Bvsmod(Box>, Box>), + // Bvult(Box>, Box>), + // Bvslt(Box>, Box>), + // Bvule(Box>, Box>), + // Bvsle(Box>, Box>), + // Bvuge(Box>, Box>), + // Bvsge(Box>, Box>), + // Bvugt(Box>, Box>), + // Bvsgt(Box>, Box>), + // Extract(u32, u32, Box>), + ZeroExtend(n, exp) => match tctx.infer(exp).unwrap() { + smtlib::Ty::BitVec(w) => SpecExpr::Op { + op: SpecOp::ZeroExt, + args: vec![SpecExpr::ConstInt { + val: (n + w).try_into().unwrap(), + pos: Pos::default(), + }], + pos: Pos::default(), + }, + _ => panic!("zero extend applies to bitvector types"), + }, + // SignExtend(u32, Box>), + // Bvshl(Box>, Box>), + // Bvlshr(Box>, Box>), + // Bvashr(Box>, Box>), + // Concat(Box>, Box>), + // Ite(Box>, Box>, Box>), + // App(Sym, Vec>), + // Select(Box>, Box>), + // Store(Box>, Box>, Box>), + // Distinct(Vec>), + // FPConstant(FPConstant, u32, u32), + // FPRoundingMode(FPRoundingMode), + // FPUnary(FPUnary, Box>), + // FPRoundingUnary(FPRoundingUnary, Box>, Box>), + // FPBinary(FPBinary, Box>, Box>), + // FPRoundingBinary(FPRoundingBinary, Box>, Box>, Box>), + // FPfma(Box>, Box>, Box>, Box>), + _ => todo!("expression: {:?}", exp), + } +} From 8745a0429c139c90541da6b284d3063e61941fca Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Mon, 1 Jan 2024 12:19:53 -0500 Subject: [PATCH 39/73] more spec translation --- cranelift/isle/veri/veri_engine/src/emit.rs | 116 +++++++++++++++++--- 1 file changed, 103 insertions(+), 13 deletions(-) diff --git a/cranelift/isle/veri/veri_engine/src/emit.rs b/cranelift/isle/veri/veri_engine/src/emit.rs index 6c87e9b851eb..d92e925c8175 100644 --- a/cranelift/isle/veri/veri_engine/src/emit.rs +++ b/cranelift/isle/veri/veri_engine/src/emit.rs @@ -597,14 +597,16 @@ fn exp_to_spec(exp: &smtlib::Exp, tctx: &TypeContext) -> SpecExpr { // Bvnot(Box>), // Bvand(Box>, Box>), // Bvor(Box>, Box>), - // Bvxor(Box>, Box>), // Bvnand(Box>, Box>), // Bvnor(Box>, Box>), // Bvxnor(Box>, Box>), // Bvneg(Box>), - // Bvadd(Box>, Box>), - // Bvsub(Box>, Box>), - // Bvmul(Box>, Box>), + Bvxor(lhs, rhs) | Bvadd(lhs, rhs) | Bvsub(lhs, rhs) | Bvmul(lhs, rhs) => spec_binary( + exp_spec_op(exp), + exp_to_spec(lhs, tctx), + exp_to_spec(rhs, tctx), + ), + // Bvudiv(Box>, Box>), // Bvsdiv(Box>, Box>), // Bvurem(Box>, Box>), @@ -618,18 +620,22 @@ fn exp_to_spec(exp: &smtlib::Exp, tctx: &TypeContext) -> SpecExpr { // Bvsge(Box>, Box>), // Bvugt(Box>, Box>), // Bvsgt(Box>, Box>), - // Extract(u32, u32, Box>), + Extract(i, j, exp) => spec_ternary( + SpecOp::Extract, + spec_const_int(*i), + spec_const_int(*j), + exp_to_spec(exp, tctx), + ), + ZeroExtend(n, exp) => match tctx.infer(exp).unwrap() { - smtlib::Ty::BitVec(w) => SpecExpr::Op { - op: SpecOp::ZeroExt, - args: vec![SpecExpr::ConstInt { - val: (n + w).try_into().unwrap(), - pos: Pos::default(), - }], - pos: Pos::default(), - }, + smtlib::Ty::BitVec(w) => spec_binary( + SpecOp::ZeroExt, + spec_const_int(n + w), + exp_to_spec(exp, tctx), + ), _ => panic!("zero extend applies to bitvector types"), }, + // SignExtend(u32, Box>), // Bvshl(Box>, Box>), // Bvlshr(Box>, Box>), @@ -650,3 +656,87 @@ fn exp_to_spec(exp: &smtlib::Exp, tctx: &TypeContext) -> SpecExpr { _ => todo!("expression: {:?}", exp), } } + +fn exp_spec_op(exp: &smtlib::Exp) -> SpecOp { + use smtlib::Exp::*; + match exp { + // Bits(Vec), + // Bits64(B64), + // Enum(EnumMember), + // Bool(bool), + // Eq(Box>, Box>), + // Neq(Box>, Box>), + // And(Box>, Box>), + // Or(Box>, Box>), + // Not(Box>), + // Bvnot(Box>), + // Bvand(Box>, Box>), + // Bvor(Box>, Box>), + Bvxor(..) => SpecOp::BVXor, + // Bvnand(Box>, Box>), + // Bvnor(Box>, Box>), + // Bvxnor(Box>, Box>), + // Bvneg(Box>), + Bvadd(..) => SpecOp::BVAdd, + Bvsub(..) => SpecOp::BVSub, + Bvmul(..) => SpecOp::BVMul, + // Bvudiv(Box>, Box>), + // Bvsdiv(Box>, Box>), + // Bvurem(Box>, Box>), + // Bvsrem(Box>, Box>), + // Bvsmod(Box>, Box>), + // Bvult(Box>, Box>), + // Bvslt(Box>, Box>), + // Bvule(Box>, Box>), + // Bvsle(Box>, Box>), + // Bvuge(Box>, Box>), + // Bvsge(Box>, Box>), + // Bvugt(Box>, Box>), + // Bvsgt(Box>, Box>), + + // SignExtend(u32, Box>), + // Bvshl(Box>, Box>), + // Bvlshr(Box>, Box>), + // Bvashr(Box>, Box>), + // Concat(Box>, Box>), + // Ite(Box>, Box>, Box>), + // App(Sym, Vec>), + // Select(Box>, Box>), + // Store(Box>, Box>, Box>), + // Distinct(Vec>), + // FPConstant(FPConstant, u32, u32), + // FPRoundingMode(FPRoundingMode), + // FPUnary(FPUnary, Box>), + // FPRoundingUnary(FPRoundingUnary, Box>, Box>), + // FPBinary(FPBinary, Box>, Box>), + // FPRoundingBinary(FPRoundingBinary, Box>, Box>, Box>), + // FPfma(Box>, Box>, Box>, Box>), + _ => todo!("spec op: {:?}", exp), + } +} + +fn spec_const_int(x: I) -> SpecExpr +where + i128: From, +{ + SpecExpr::ConstInt { + val: x.try_into().unwrap(), + pos: Pos::default(), + } +} + +fn spec_binary(op: SpecOp, x: SpecExpr, y: SpecExpr) -> SpecExpr { + SpecExpr::Op { + op, + args: vec![x, y], + pos: Pos::default(), + } +} + +fn spec_ternary(op: SpecOp, x: SpecExpr, y: SpecExpr, z: SpecExpr) -> SpecExpr { + SpecExpr::Op { + op, + args: vec![x, y, z], + pos: Pos::default(), + } +} From 493aa3dafdc983ef23a7c398491a44111326a9df Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Mon, 1 Jan 2024 15:47:19 -0500 Subject: [PATCH 40/73] even more spec translation --- cranelift/isle/veri/veri_engine/src/emit.rs | 78 ++++++++++++++++----- 1 file changed, 62 insertions(+), 16 deletions(-) diff --git a/cranelift/isle/veri/veri_engine/src/emit.rs b/cranelift/isle/veri/veri_engine/src/emit.rs index d92e925c8175..85f6164e78fe 100644 --- a/cranelift/isle/veri/veri_engine/src/emit.rs +++ b/cranelift/isle/veri/veri_engine/src/emit.rs @@ -552,14 +552,19 @@ fn event_to_spec(event: &Event, tctx: &mut TypeContext) -> Option Option { match def { - smtlib::Def::DefineConst(sym, exp) => Some(SpecExpr::Op { - op: SpecOp::Eq, - args: vec![ - exp_to_spec(&smtlib::Exp::Var(*sym), tctx), - exp_to_spec(exp, tctx), - ], - pos: Pos::default(), - }), + smtlib::Def::DefineConst(v, exp) => { + let ty = tctx.infer(exp).expect("SMT expression was badly-typed"); + tctx.ty.insert(*v, ty.clone()); + + Some(SpecExpr::Op { + op: SpecOp::Eq, + args: vec![ + exp_to_spec(&smtlib::Exp::Var(*v), tctx), + exp_to_spec(exp, tctx), + ], + pos: Pos::default(), + }) + } smtlib::Def::DeclareConst(v, ty) => { tctx.ty.insert(*v, ty.clone()); @@ -586,7 +591,11 @@ fn exp_to_spec(exp: &smtlib::Exp, tctx: &TypeContext) -> SpecExpr { }, // Bits(Vec), - // Bits64(B64), + Bits(bits) => spec_bits(bits), + Bits64(bv) => spec_const_bit_vector( + bv.lower_u64().try_into().unwrap(), + bv.len().try_into().unwrap(), + ), // Enum(EnumMember), // Bool(bool), // Eq(Box>, Box>), @@ -594,6 +603,8 @@ fn exp_to_spec(exp: &smtlib::Exp, tctx: &TypeContext) -> SpecExpr { // And(Box>, Box>), // Or(Box>, Box>), // Not(Box>), + Not(exp) | Bvnot(exp) => spec_unary(exp_spec_op(exp), exp_to_spec(exp, tctx)), + // Bvnot(Box>), // Bvand(Box>, Box>), // Bvor(Box>, Box>), @@ -601,11 +612,13 @@ fn exp_to_spec(exp: &smtlib::Exp, tctx: &TypeContext) -> SpecExpr { // Bvnor(Box>, Box>), // Bvxnor(Box>, Box>), // Bvneg(Box>), - Bvxor(lhs, rhs) | Bvadd(lhs, rhs) | Bvsub(lhs, rhs) | Bvmul(lhs, rhs) => spec_binary( - exp_spec_op(exp), - exp_to_spec(lhs, tctx), - exp_to_spec(rhs, tctx), - ), + Bvxor(lhs, rhs) | Bvadd(lhs, rhs) | Bvsub(lhs, rhs) | Bvmul(lhs, rhs) | Bvshl(lhs, rhs) => { + spec_binary( + exp_spec_op(exp), + exp_to_spec(lhs, tctx), + exp_to_spec(rhs, tctx), + ) + } // Bvudiv(Box>, Box>), // Bvsdiv(Box>, Box>), @@ -637,7 +650,6 @@ fn exp_to_spec(exp: &smtlib::Exp, tctx: &TypeContext) -> SpecExpr { }, // SignExtend(u32, Box>), - // Bvshl(Box>, Box>), // Bvlshr(Box>, Box>), // Bvashr(Box>, Box>), // Concat(Box>, Box>), @@ -669,6 +681,7 @@ fn exp_spec_op(exp: &smtlib::Exp) -> SpecOp { // And(Box>, Box>), // Or(Box>, Box>), // Not(Box>), + Not(..) => SpecOp::Not, // Bvnot(Box>), // Bvand(Box>, Box>), // Bvor(Box>, Box>), @@ -695,7 +708,7 @@ fn exp_spec_op(exp: &smtlib::Exp) -> SpecOp { // Bvsgt(Box>, Box>), // SignExtend(u32, Box>), - // Bvshl(Box>, Box>), + Bvshl(..) => SpecOp::BVShl, // Bvlshr(Box>, Box>), // Bvashr(Box>, Box>), // Concat(Box>, Box>), @@ -725,6 +738,39 @@ where } } +fn spec_const_bit_vector(val: i128, width: i8) -> SpecExpr { + assert!(width >= 0); + SpecExpr::ConstBitVec { + val, + width, + pos: Pos::default(), + } +} + +fn spec_bits(bits: &[bool]) -> SpecExpr { + let width = bits.len(); + if width >= 128 { + todo!("support width 128+ bit vectors") + } + + let mut val: i128 = 0; + for (i, bit) in bits.iter().enumerate() { + if *bit { + val |= 1 << i; + } + } + + spec_const_bit_vector(val, width.try_into().unwrap()) +} + +fn spec_unary(op: SpecOp, x: SpecExpr) -> SpecExpr { + SpecExpr::Op { + op, + args: vec![x], + pos: Pos::default(), + } +} + fn spec_binary(op: SpecOp, x: SpecExpr, y: SpecExpr) -> SpecExpr { SpecExpr::Op { op, From 475328c04afa985d20ba69629d7ad4a816479205 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Mon, 1 Jan 2024 16:36:18 -0500 Subject: [PATCH 41/73] use concat to support arbitrary length bitvectors --- cranelift/isle/isle/src/ast.rs | 1 + cranelift/isle/veri/veri_engine/src/emit.rs | 27 +++++++++++---------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/cranelift/isle/isle/src/ast.rs b/cranelift/isle/isle/src/ast.rs index 5aefba303add..194d9dd8a13d 100644 --- a/cranelift/isle/isle/src/ast.rs +++ b/cranelift/isle/isle/src/ast.rs @@ -102,6 +102,7 @@ pub enum SpecExpr { }, /// An operator that matches a constant bitvector value. ConstBitVec { + // TODO(mbm): support arbitrary length bitvectors val: i128, width: i8, pos: Pos, diff --git a/cranelift/isle/veri/veri_engine/src/emit.rs b/cranelift/isle/veri/veri_engine/src/emit.rs index 85f6164e78fe..918324724068 100644 --- a/cranelift/isle/veri/veri_engine/src/emit.rs +++ b/cranelift/isle/veri/veri_engine/src/emit.rs @@ -748,19 +748,20 @@ fn spec_const_bit_vector(val: i128, width: i8) -> SpecExpr { } fn spec_bits(bits: &[bool]) -> SpecExpr { - let width = bits.len(); - if width >= 128 { - todo!("support width 128+ bit vectors") - } - - let mut val: i128 = 0; - for (i, bit) in bits.iter().enumerate() { - if *bit { - val |= 1 << i; - } - } - - spec_const_bit_vector(val, width.try_into().unwrap()) + // TODO(mbm): verify endianness assumption about Vec and test multi-chunk case + bits.chunks(64) + .map(|chunk| { + let mut val: i128 = 0; + for (i, bit) in chunk.iter().enumerate() { + if *bit { + val |= 1 << i; + } + } + spec_const_bit_vector(val, 64) + }) + .rev() + .reduce(|acc, bv| spec_binary(SpecOp::Concat, acc, bv)) + .unwrap() } fn spec_unary(op: SpecOp, x: SpecExpr) -> SpecExpr { From 6ef5e5069f2f3e8fb64813026527d7025dd1c578 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Mon, 1 Jan 2024 17:00:31 -0500 Subject: [PATCH 42/73] handle more spec translation --- cranelift/isle/veri/veri_engine/src/emit.rs | 81 ++++++++++++--------- 1 file changed, 46 insertions(+), 35 deletions(-) diff --git a/cranelift/isle/veri/veri_engine/src/emit.rs b/cranelift/isle/veri/veri_engine/src/emit.rs index 918324724068..9ef73a119111 100644 --- a/cranelift/isle/veri/veri_engine/src/emit.rs +++ b/cranelift/isle/veri/veri_engine/src/emit.rs @@ -589,36 +589,37 @@ fn exp_to_spec(exp: &smtlib::Exp, tctx: &TypeContext) -> SpecExpr { var: Ident(format!("v{}", v), Pos::default()), pos: Pos::default(), }, - - // Bits(Vec), Bits(bits) => spec_bits(bits), Bits64(bv) => spec_const_bit_vector( bv.lower_u64().try_into().unwrap(), bv.len().try_into().unwrap(), ), // Enum(EnumMember), - // Bool(bool), - // Eq(Box>, Box>), + Bool(b) => spec_const_bool(*b), // Neq(Box>, Box>), - // And(Box>, Box>), - // Or(Box>, Box>), - // Not(Box>), - Not(exp) | Bvnot(exp) => spec_unary(exp_spec_op(exp), exp_to_spec(exp, tctx)), + Not(x) | Bvnot(x) => spec_unary(exp_spec_op(exp), exp_to_spec(x, tctx)), // Bvnot(Box>), - // Bvand(Box>, Box>), - // Bvor(Box>, Box>), // Bvnand(Box>, Box>), // Bvnor(Box>, Box>), // Bvxnor(Box>, Box>), // Bvneg(Box>), - Bvxor(lhs, rhs) | Bvadd(lhs, rhs) | Bvsub(lhs, rhs) | Bvmul(lhs, rhs) | Bvshl(lhs, rhs) => { - spec_binary( - exp_spec_op(exp), - exp_to_spec(lhs, tctx), - exp_to_spec(rhs, tctx), - ) - } + Eq(lhs, rhs) + | And(lhs, rhs) + | Or(lhs, rhs) + | Bvand(lhs, rhs) + | Bvor(lhs, rhs) + | Bvxor(lhs, rhs) + | Bvadd(lhs, rhs) + | Bvsub(lhs, rhs) + | Bvmul(lhs, rhs) + | Bvshl(lhs, rhs) + | Bvlshr(lhs, rhs) + | Concat(lhs, rhs) => spec_binary( + exp_spec_op(exp), + exp_to_spec(lhs, tctx), + exp_to_spec(rhs, tctx), + ), // Bvudiv(Box>, Box>), // Bvsdiv(Box>, Box>), @@ -640,20 +641,24 @@ fn exp_to_spec(exp: &smtlib::Exp, tctx: &TypeContext) -> SpecExpr { exp_to_spec(exp, tctx), ), - ZeroExtend(n, exp) => match tctx.infer(exp).unwrap() { + ZeroExtend(n, x) | SignExtend(n, x) => match tctx.infer(x).unwrap() { smtlib::Ty::BitVec(w) => spec_binary( - SpecOp::ZeroExt, + exp_spec_op(exp), spec_const_int(n + w), - exp_to_spec(exp, tctx), + exp_to_spec(x, tctx), ), - _ => panic!("zero extend applies to bitvector types"), + _ => panic!("extension applies to bitvector types"), }, - // SignExtend(u32, Box>), // Bvlshr(Box>, Box>), // Bvashr(Box>, Box>), - // Concat(Box>, Box>), - // Ite(Box>, Box>, Box>), + Ite(c, t, e) => spec_ternary( + SpecOp::If, + exp_to_spec(c, tctx), + exp_to_spec(t, tctx), + exp_to_spec(e, tctx), + ), + // App(Sym, Vec>), // Select(Box>, Box>), // Store(Box>, Box>, Box>), @@ -676,15 +681,14 @@ fn exp_spec_op(exp: &smtlib::Exp) -> SpecOp { // Bits64(B64), // Enum(EnumMember), // Bool(bool), - // Eq(Box>, Box>), + Eq(..) => SpecOp::Eq, // Neq(Box>, Box>), - // And(Box>, Box>), - // Or(Box>, Box>), - // Not(Box>), + And(..) => SpecOp::And, + Or(..) => SpecOp::Or, Not(..) => SpecOp::Not, - // Bvnot(Box>), - // Bvand(Box>, Box>), - // Bvor(Box>, Box>), + Bvnot(..) => SpecOp::BVNot, + Bvand(..) => SpecOp::BVAnd, + Bvor(..) => SpecOp::BVOr, Bvxor(..) => SpecOp::BVXor, // Bvnand(Box>, Box>), // Bvnor(Box>, Box>), @@ -706,12 +710,12 @@ fn exp_spec_op(exp: &smtlib::Exp) -> SpecOp { // Bvsge(Box>, Box>), // Bvugt(Box>, Box>), // Bvsgt(Box>, Box>), - - // SignExtend(u32, Box>), + ZeroExtend(..) => SpecOp::ZeroExt, + SignExtend(..) => SpecOp::SignExt, Bvshl(..) => SpecOp::BVShl, - // Bvlshr(Box>, Box>), + Bvlshr(..) => SpecOp::BVLshr, // Bvashr(Box>, Box>), - // Concat(Box>, Box>), + Concat(..) => SpecOp::Concat, // Ite(Box>, Box>, Box>), // App(Sym, Vec>), // Select(Box>, Box>), @@ -738,6 +742,13 @@ where } } +fn spec_const_bool(b: bool) -> SpecExpr { + SpecExpr::ConstBool { + val: if b { 1 } else { 0 }, + pos: Pos::default(), + } +} + fn spec_const_bit_vector(val: i128, width: i8) -> SpecExpr { assert!(width >= 0); SpecExpr::ConstBitVec { From e85162dbcb881b7798a181e8c4e0727ad247c787 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Wed, 3 Jan 2024 06:57:37 -0500 Subject: [PATCH 43/73] isle: support printing of any Printable nodes --- cranelift/isle/isle/src/printer.rs | 96 +++++++++++++++++------------- 1 file changed, 55 insertions(+), 41 deletions(-) diff --git a/cranelift/isle/isle/src/printer.rs b/cranelift/isle/isle/src/printer.rs index 19608d081b9d..2af62a370959 100644 --- a/cranelift/isle/isle/src/printer.rs +++ b/cranelift/isle/isle/src/printer.rs @@ -7,23 +7,33 @@ use crate::error::Errors; use pretty::{Doc, Pretty, RcAllocator, RcDoc}; use std::io::Write; -pub fn print(defs: &Defs, width: usize, out: &mut W) -> Result<(), Errors> +pub trait Printable { + fn to_doc(&self) -> RcDoc<()>; +} + +pub fn print(node: &N, width: usize, out: &mut W) -> Result<(), Errors> where + N: Printable, W: ?Sized + Write, { - defs.to_doc() + node.to_doc() .render(width, out) .map_err(|e| Errors::from_io(e, "failed to print isle")) } -impl Defs { +pub fn dump(node: &N) -> Result<(), Errors> { + let mut stdout = std::io::stdout(); + print(node, 78, &mut stdout) +} + +impl Printable for Defs { fn to_doc(&self) -> RcDoc<()> { let sep = RcDoc::hardline().append(Doc::hardline()); RcDoc::intersperse(self.defs.iter().map(|d| d.to_doc()), sep).append(Doc::hardline()) } } -impl Def { +impl Printable for Def { fn to_doc(&self) -> RcDoc<()> { match self { Def::Pragma(_) => unimplemented!("pragmas not supported"), @@ -79,29 +89,7 @@ impl Def { parts.push(d.ret_ty.to_doc()); sexp(parts) } - Def::Spec(ref s) => { - let mut parts = vec![RcDoc::text("spec")]; - parts.push(sexp( - Vec::from([s.term.to_doc()]) - .into_iter() - .chain(s.args.iter().map(|a| a.to_doc())), - )); - if !s.provides.is_empty() { - parts.push(sexp( - Vec::from([RcDoc::text("provide")]) - .into_iter() - .chain(s.provides.iter().map(|e| e.to_doc())), - )); - } - if !s.requires.is_empty() { - parts.push(sexp( - Vec::from([RcDoc::text("require")]) - .into_iter() - .chain(s.requires.iter().map(|e| e.to_doc())), - )); - } - sexp(parts) - } + Def::Spec(ref s) => s.to_doc(), Def::Model(ref m) => sexp(vec![RcDoc::text("model"), m.name.to_doc(), m.val.to_doc()]), Def::Form(ref f) => { let mut parts = vec![RcDoc::text("form")]; @@ -129,13 +117,13 @@ impl Def { } } -impl Ident { +impl Printable for Ident { fn to_doc(&self) -> RcDoc<()> { RcDoc::text(self.0.clone()) } } -impl TypeValue { +impl Printable for TypeValue { fn to_doc(&self) -> RcDoc<()> { match self { TypeValue::Primitive(ref name, _) => { @@ -151,7 +139,7 @@ impl TypeValue { } } -impl Variant { +impl Printable for Variant { fn to_doc(&self) -> RcDoc<()> { sexp( // TODO(mbm): convenience for sexp with a fixed first element @@ -162,13 +150,13 @@ impl Variant { } } -impl Field { +impl Printable for Field { fn to_doc(&self) -> RcDoc<()> { sexp(vec![self.name.to_doc(), self.ty.to_doc()]) } } -impl ModelValue { +impl Printable for ModelValue { fn to_doc(&self) -> RcDoc<()> { match self { ModelValue::TypeValue(ref mt) => sexp(vec![RcDoc::text("type"), mt.to_doc()]), @@ -183,7 +171,7 @@ impl ModelValue { } } -impl ModelType { +impl Printable for ModelType { fn to_doc(&self) -> RcDoc<()> { match self { ModelType::Int => RcDoc::text("Int"), @@ -194,7 +182,7 @@ impl ModelType { } } -impl Signature { +impl Printable for Signature { fn to_doc(&self) -> RcDoc<()> { sexp(vec![ sexp( @@ -208,7 +196,7 @@ impl Signature { } } -impl SpecExpr { +impl Printable for SpecExpr { fn to_doc(&self) -> RcDoc<()> { match self { SpecExpr::ConstInt { val, .. } => RcDoc::as_string(val), @@ -232,7 +220,7 @@ impl SpecExpr { } } -impl SpecOp { +impl Printable for SpecOp { fn to_doc(&self) -> RcDoc<()> { RcDoc::text(match self { SpecOp::Eq => "=", @@ -288,7 +276,33 @@ impl SpecOp { } } -impl Pattern { +impl Printable for Spec { + fn to_doc(&self) -> RcDoc<()> { + let mut parts = vec![RcDoc::text("spec")]; + parts.push(sexp( + Vec::from([self.term.to_doc()]) + .into_iter() + .chain(self.args.iter().map(|a| a.to_doc())), + )); + if !self.provides.is_empty() { + parts.push(sexp( + Vec::from([RcDoc::text("provide")]) + .into_iter() + .chain(self.provides.iter().map(|e| e.to_doc())), + )); + } + if !self.requires.is_empty() { + parts.push(sexp( + Vec::from([RcDoc::text("require")]) + .into_iter() + .chain(self.requires.iter().map(|e| e.to_doc())), + )); + } + sexp(parts) + } +} + +impl Printable for Pattern { fn to_doc(&self) -> RcDoc<()> { match self { Pattern::Var { var, .. } => var.to_doc(), @@ -315,7 +329,7 @@ impl Pattern { } } -impl IfLet { +impl Printable for IfLet { fn to_doc(&self) -> RcDoc<()> { // TODO(mbm): `if` shorthand when pattern is wildcard sexp(vec![ @@ -326,7 +340,7 @@ impl IfLet { } } -impl Expr { +impl Printable for Expr { fn to_doc(&self) -> RcDoc<()> { match self { Expr::Term { sym, args, .. } => sexp( @@ -349,13 +363,13 @@ impl Expr { } } -impl LetDef { +impl Printable for LetDef { fn to_doc(&self) -> RcDoc<()> { sexp(vec![self.var.to_doc(), self.ty.to_doc(), self.val.to_doc()]) } } -impl Extern { +impl Printable for Extern { fn to_doc(&self) -> RcDoc<()> { match self { Extern::Extractor { From 02a46a7704d76330ac8b9ace1e4a27182cacfb4c Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Wed, 3 Jan 2024 06:57:56 -0500 Subject: [PATCH 44/73] isle: Errors implement std::error::Error --- cranelift/isle/isle/src/error.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cranelift/isle/isle/src/error.rs b/cranelift/isle/isle/src/error.rs index f9c8468c8aec..f0274febc68e 100644 --- a/cranelift/isle/isle/src/error.rs +++ b/cranelift/isle/isle/src/error.rs @@ -5,6 +5,7 @@ use std::sync::Arc; use crate::lexer::Pos; /// A collection of errors from attempting to compile some ISLE source files. +#[derive(Debug)] pub struct Errors { /// The individual errors. pub errors: Vec, @@ -12,7 +13,9 @@ pub struct Errors { pub(crate) file_texts: Vec>, } -impl std::fmt::Debug for Errors { +impl std::error::Error for Errors {} + +impl std::fmt::Display for Errors { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { if self.errors.is_empty() { return Ok(()); From 814a67a2dee8f3e4f347e20445d31409f1794bcc Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Wed, 3 Jan 2024 07:01:30 -0500 Subject: [PATCH 45/73] emit: print generated spec --- cranelift/isle/veri/veri_engine/src/emit.rs | 37 ++++++++++++++------- 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/cranelift/isle/veri/veri_engine/src/emit.rs b/cranelift/isle/veri/veri_engine/src/emit.rs index 9ef73a119111..8257004d2f5c 100644 --- a/cranelift/isle/veri/veri_engine/src/emit.rs +++ b/cranelift/isle/veri/veri_engine/src/emit.rs @@ -4,9 +4,9 @@ use cranelift_codegen::settings; use cranelift_codegen::AllocationConsumer; use cranelift_codegen::MachBuffer; use cranelift_codegen::MachInstEmit; -use cranelift_isle::ast::Ident; -use cranelift_isle::ast::{SpecExpr, SpecOp}; +use cranelift_isle::ast::{Ident, Spec, SpecExpr, SpecOp}; use cranelift_isle::lexer::Pos; +use cranelift_isle::printer; use crossbeam::queue::SegQueue; use isla::opts; use isla_lib::bitvector::{b64::B64, BV}; @@ -112,13 +112,13 @@ fn main() -> anyhow::Result<()> { rm: xreg(14), cond: Cond::Hs, }, - Inst::CCmp { - size: OperandSize::Size64, - rn: xreg(22), - rm: xreg(1), - nzcv: NZCV::new(false, false, true, true), - cond: Cond::Eq, - }, + // Inst::CCmp { + // size: OperandSize::Size64, + // rn: xreg(22), + // rm: xreg(1), + // nzcv: NZCV::new(false, false, true, true), + // cond: Cond::Eq, + // }, Inst::AluRRImmShift { alu_op: ALUOp::Lsr, size: OperandSize::Size64, @@ -175,7 +175,7 @@ fn main() -> anyhow::Result<()> { // Generate spec. let spec = trace_to_spec(&events); - println!("spec = {spec:?}"); + printer::dump(&spec)?; println!(""); } @@ -535,7 +535,16 @@ impl TypeContext { } } -fn trace_to_spec(events: &Vec>) -> Vec { +fn trace_to_spec(events: &Vec>) -> Spec { + Spec { + term: spec_ident("placeholder".to_string()), + args: vec![], + requires: vec![], + provides: trace_provides(events), + } +} + +fn trace_provides(events: &Vec>) -> Vec { let mut tctx = TypeContext::new(); events .iter() @@ -586,7 +595,7 @@ fn exp_to_spec(exp: &smtlib::Exp, tctx: &TypeContext) -> SpecExpr { use smtlib::Exp::*; match exp { Var(v) => SpecExpr::Var { - var: Ident(format!("v{}", v), Pos::default()), + var: spec_ident(format!("v{}", v)), pos: Pos::default(), }, Bits(bits) => spec_bits(bits), @@ -798,3 +807,7 @@ fn spec_ternary(op: SpecOp, x: SpecExpr, y: SpecExpr, z: SpecExpr) -> SpecExpr { pos: Pos::default(), } } + +fn spec_ident(id: String) -> Ident { + Ident(id, Pos::default()) +} From 97e8582d8d839f2ffe1876f21a34023e362a5483 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Wed, 3 Jan 2024 10:50:18 -0500 Subject: [PATCH 46/73] emit: tolerate spec conversion failure --- cranelift/isle/veri/veri_engine/src/emit.rs | 65 ++++++++++++--------- 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/cranelift/isle/veri/veri_engine/src/emit.rs b/cranelift/isle/veri/veri_engine/src/emit.rs index 8257004d2f5c..60393071120c 100644 --- a/cranelift/isle/veri/veri_engine/src/emit.rs +++ b/cranelift/isle/veri/veri_engine/src/emit.rs @@ -29,6 +29,7 @@ fn main() -> anyhow::Result<()> { // Command-line options. let mut opts = opts::common_opts(); opts.optflag("", "filter", "filter relevant events from the trace"); + opts.optflag("", "spec", "convert traces to veri-isle specs"); // Build ISLA architecture. let mut hasher = Sha256::new(); @@ -112,13 +113,13 @@ fn main() -> anyhow::Result<()> { rm: xreg(14), cond: Cond::Hs, }, - // Inst::CCmp { - // size: OperandSize::Size64, - // rn: xreg(22), - // rm: xreg(1), - // nzcv: NZCV::new(false, false, true, true), - // cond: Cond::Eq, - // }, + Inst::CCmp { + size: OperandSize::Size64, + rn: xreg(22), + rm: xreg(1), + nzcv: NZCV::new(false, false, true, true), + cond: Cond::Eq, + }, Inst::AluRRImmShift { alu_op: ALUOp::Lsr, size: OperandSize::Size64, @@ -174,8 +175,12 @@ fn main() -> anyhow::Result<()> { write_events(&events, &iarch)?; // Generate spec. - let spec = trace_to_spec(&events); - printer::dump(&spec)?; + if matches.opt_present("spec") { + match trace_to_spec(&events) { + Ok(spec) => printer::dump(&spec)?, + Err(err) => println!("spec conversion failed: {}", err), + }; + } println!(""); } @@ -535,59 +540,65 @@ impl TypeContext { } } -fn trace_to_spec(events: &Vec>) -> Spec { - Spec { +fn trace_to_spec(events: &Vec>) -> anyhow::Result { + Ok(Spec { term: spec_ident("placeholder".to_string()), args: vec![], requires: vec![], - provides: trace_provides(events), - } + provides: trace_provides(events)?, + }) } -fn trace_provides(events: &Vec>) -> Vec { +fn trace_provides(events: &Vec>) -> anyhow::Result> { + let mut provides = Vec::new(); let mut tctx = TypeContext::new(); - events - .iter() - .filter_map(|e| event_to_spec(e, &mut tctx)) - .collect() + for event in events { + if let Some(exp) = event_to_spec(event, &mut tctx)? { + provides.push(exp); + } + } + Ok(provides) } -fn event_to_spec(event: &Event, tctx: &mut TypeContext) -> Option { +fn event_to_spec( + event: &Event, + tctx: &mut TypeContext, +) -> anyhow::Result> { match event { Event::Smt(def, attr, ..) if !attr.is_uninteresting() => smt_to_spec(def, tctx), - _ => None, + _ => Ok(None), } } -fn smt_to_spec(def: &smtlib::Def, tctx: &mut TypeContext) -> Option { +fn smt_to_spec(def: &smtlib::Def, tctx: &mut TypeContext) -> anyhow::Result> { match def { smtlib::Def::DefineConst(v, exp) => { let ty = tctx.infer(exp).expect("SMT expression was badly-typed"); tctx.ty.insert(*v, ty.clone()); - Some(SpecExpr::Op { + Ok(Some(SpecExpr::Op { op: SpecOp::Eq, args: vec![ exp_to_spec(&smtlib::Exp::Var(*v), tctx), exp_to_spec(exp, tctx), ], pos: Pos::default(), - }) + })) } smtlib::Def::DeclareConst(v, ty) => { tctx.ty.insert(*v, ty.clone()); - None + Ok(None) } smtlib::Def::DeclareFun(v, params, ret) => { tctx.fun.insert(*v, (params.clone(), ret.clone())); - None + Ok(None) } - smtlib::Def::DefineEnum(..) => None, + smtlib::Def::DefineEnum(..) => Ok(None), - _ => todo!("smt def: {:?}", def), + _ => anyhow::bail!("unsupported smt def: {:?}", def), } } From 73f231f0f4cd8096f5f6176a84d32e488c3be022 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Thu, 11 Jan 2024 22:20:11 -0500 Subject: [PATCH 47/73] isaspec adhoc tool for building specs --- .../isle/veri/veri_engine/src/bin/isaspec.rs | 862 ++++++++++++++++++ 1 file changed, 862 insertions(+) create mode 100644 cranelift/isle/veri/veri_engine/src/bin/isaspec.rs diff --git a/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs b/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs new file mode 100644 index 000000000000..65d3f1860e2c --- /dev/null +++ b/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs @@ -0,0 +1,862 @@ +use cranelift_codegen::isa::aarch64::inst::*; +use cranelift_codegen::settings; +use cranelift_codegen::AllocationConsumer; +use cranelift_codegen::MachBuffer; +use cranelift_codegen::MachInstEmit; +use cranelift_isle::ast::{Ident, Spec, SpecExpr, SpecOp}; +use cranelift_isle::lexer::Pos; +use cranelift_isle::printer; +use crossbeam::queue::SegQueue; +use isla::opts; +use isla_lib::bitvector::{b64::B64, BV}; +use isla_lib::error::IslaError; +use isla_lib::executor::{self, LocalFrame, TaskState}; +use isla_lib::init::{initialize_architecture, Initialized}; +use isla_lib::ir::Name; +use isla_lib::ir::{AssertionMode, Val}; +use isla_lib::memory::Memory; +use isla_lib::simplify::{self, WriteOpts}; +use isla_lib::smt::smtlib; +use isla_lib::smt::{self, Checkpoint, Event, Solver, Sym}; +use isla_lib::zencode; +use sha2::{Digest, Sha256}; +use std::collections::{HashMap, HashSet}; +use std::io::prelude::*; +use std::io::BufWriter; +use std::path::PathBuf; +use std::sync::Arc; + +fn main() -> anyhow::Result<()> { + // Command-line options. + let mut opts = opts::common_opts(); + opts.optflag("", "filter", "filter relevant events from the trace"); + //opts.optflag("", "spec", "convert traces to veri-isle specs"); + + // Build ISLA architecture. + let mut hasher = Sha256::new(); + let (matches, arch) = opts::parse::(&mut hasher, &opts); + let opts::CommonOpts { + num_threads: _, + mut arch, + symtab, + type_info, + isa_config, + source_path: _, + } = opts::parse_with_arch(&mut hasher, &opts, &matches, &arch); + let use_model_reg_init = true; + let iarch = initialize_architecture( + &mut arch, + symtab, + type_info, + &isa_config, + AssertionMode::Optimistic, + use_model_reg_init, + ); + + // Assemble and trace instructions. + let inst = Inst::AluRRR { + alu_op: ALUOp::Add, + size: OperandSize::Size64, + rd: writable_xreg(4), + rn: xreg(5), + rm: xreg(6), + }; + let cfg = SpecConfig { + term: "MInst.AluRRR".to_string(), + args: ["alu_op", "size", "rd", "rn", "rm"] + .map(String::from) + .to_vec(), + reg_read: HashMap::from([ + ("R5".to_string(), "rn".to_string()), + ("R6".to_string(), "rm".to_string()), + ]), + reg_write: HashMap::from([("R4".to_string(), "rd".to_string())]), + var_prefix: "v".to_string(), + }; + + // Assemble. + let opcodes = opcodes(&inst); + assert_eq!(opcodes.len(), 1); + let opcode = opcodes[0]; + + // Show assembly. + let asm = inst.print_with_state(&mut EmitState::default(), &mut AllocationConsumer::new(&[])); + + println!("--------------------------------------------------"); + println!("inst = {inst:?}"); + println!("opcode = {opcode:08x}"); + println!("asm = {asm}"); + println!(""); + + // ISLA trace. + let paths = trace_opcode(opcode, &iarch)?; + assert_eq!(paths.len(), 1); + let events = &paths[0]; + + // Dump. + let events = if matches.opt_present("filter") { + tree_shake(&events) + } else { + events.clone() + }; + write_events(&events, &iarch)?; + + // Generate spec. + let mut spec_converter = SpecConverter::new(cfg, &iarch); + match spec_converter.convert(&events) { + Ok(spec) => printer::dump(&spec)?, + Err(err) => println!("spec conversion failed: {}", err), + }; + + Ok(()) +} + +// struct SpecBuilder<'ir, B: BV> { +// term: String, +// params: Vec, +// inst: Inst, +// iarch: &'ir Initialized<'ir, B>, +// } +// +// impl<'ir, B: BV> SpecBuilder<'ir, B> { +// fn build(&self) -> anyhow::Result { +// // Assemble instruction. +// let opcodes = opcodes(&self.inst); +// assert_eq!(opcodes.len(), 1); +// let opcode = opcodes[0]; +// +// // ISLA trace. +// let paths = trace_opcode(opcode, &self.iarch)?; +// +// // TODO(mbm): handle multiple paths +// assert_eq!(paths.len(), 1); +// let events = &paths[0]; +// +// // Filter. +// let events = tree_shake(events); +// +// // Generate spec. +// trace_to_spec(&events) +// } +// } + +fn assemble(inst: &Inst) -> Vec { + let flags = settings::Flags::new(settings::builder()); + let emit_info = EmitInfo::new(flags); + let mut buffer = MachBuffer::new(); + inst.emit(&[], &mut buffer, &emit_info, &mut Default::default()); + let buffer = buffer.finish(&Default::default(), &mut Default::default()); + return buffer.data().to_vec(); +} + +fn opcodes(inst: &Inst) -> Vec { + let machine_code = assemble(&inst); + let mut opcodes = Vec::new(); + for opcode_bytes in machine_code.chunks(4) { + assert_eq!(opcode_bytes.len(), 4); + opcodes.push(u32::from_le_bytes(opcode_bytes.try_into().unwrap())); + } + opcodes +} + +fn trace_opcode<'ir, B: BV>( + opcode: u32, + iarch: &'ir Initialized<'ir, B>, +) -> anyhow::Result>>> { + let shared_state = &&iarch.shared_state; + + let initial_checkpoint = Checkpoint::new(); + let solver_cfg = smt::Config::new(); + let solver_ctx = smt::Context::new(solver_cfg); + let mut solver = Solver::from_checkpoint(&solver_ctx, initial_checkpoint); + let checkpoint = smt::checkpoint(&mut solver); + + let opcode_val = Val::Bits(B::from_u32(opcode)); + + let footprint_function = "zisla_footprint_no_init"; + let function_id = shared_state.symtab.lookup(&footprint_function); + let (args, ret_ty, instrs) = shared_state.functions.get(&function_id).unwrap(); + let memory = Memory::new(); + let task_state = TaskState::::new(); + let task = LocalFrame::new(function_id, args, ret_ty, Some(&[opcode_val]), instrs) + .add_lets(&iarch.lets) + .add_regs(&iarch.regs) + .set_memory(memory) + .task_with_checkpoint(0, &task_state, checkpoint); + + let num_threads = 1; + let queue = Arc::new(SegQueue::new()); + executor::start_multi( + num_threads, + None, + vec![task], + shared_state, + queue.clone(), + &executor::trace_collector, + ); + + let mut paths = Vec::new(); + loop { + match queue.pop() { + Some(Ok((_, mut events))) => { + simplify::hide_initialization(&mut events); + simplify::remove_extra_register_fields(&mut events); + simplify::remove_repeated_register_reads(&mut events); + simplify::remove_unused_register_assumptions(&mut events); + simplify::remove_unused(&mut events); + simplify::propagate_forwards_used_once(&mut events); + simplify::commute_extract(&mut events); + simplify::eval(&mut events); + + let events: Vec> = events.drain(..).rev().collect(); + paths.push(events); + } + + // Error during execution + Some(Err(err)) => { + let msg = format!("{}", err); + eprintln!( + "{}", + err.source_loc().message::( + None, + shared_state.symtab.files(), + &msg, + true, + true + ) + ); + anyhow::bail!("{}", err); + } + // Empty queue + None => break, + } + } + + Ok(paths) +} + +fn event_writes(event: &Event) -> HashSet { + match event { + Event::Smt(def, _, _) => match def { + smtlib::Def::DefineConst(v, _) => HashSet::from([*v]), + _ => HashSet::new(), + }, + Event::ReadReg(_, _, val) => val_uses(val), + _ => HashSet::new(), + } +} + +fn defns(events: &Vec>) -> HashMap { + let mut defn_idx = HashMap::new(); + for (i, event) in events.iter().enumerate() { + for sym in event_writes(event) { + defn_idx.insert(sym, i); + } + } + defn_idx +} + +fn exp_uses(exp: &smtlib::Exp) -> HashSet { + use smtlib::Exp::*; + match exp { + Var(sym) => HashSet::from([*sym]), + Bits(_) | Bits64(_) | Enum(_) | Bool(_) | FPConstant(..) | FPRoundingMode(_) => { + HashSet::new() + } + Not(exp) + | Bvnot(exp) + | Bvneg(exp) + | Extract(_, _, exp) + | ZeroExtend(_, exp) + | SignExtend(_, exp) + | FPUnary(_, exp) => exp_uses(exp), + Eq(lhs, rhs) + | Neq(lhs, rhs) + | And(lhs, rhs) + | Or(lhs, rhs) + | Bvand(lhs, rhs) + | Bvor(lhs, rhs) + | Bvxor(lhs, rhs) + | Bvnand(lhs, rhs) + | Bvnor(lhs, rhs) + | Bvxnor(lhs, rhs) + | Bvadd(lhs, rhs) + | Bvsub(lhs, rhs) + | Bvmul(lhs, rhs) + | Bvudiv(lhs, rhs) + | Bvsdiv(lhs, rhs) + | Bvurem(lhs, rhs) + | Bvsrem(lhs, rhs) + | Bvsmod(lhs, rhs) + | Bvult(lhs, rhs) + | Bvslt(lhs, rhs) + | Bvule(lhs, rhs) + | Bvsle(lhs, rhs) + | Bvuge(lhs, rhs) + | Bvsge(lhs, rhs) + | Bvugt(lhs, rhs) + | Bvsgt(lhs, rhs) + | Bvshl(lhs, rhs) + | Bvlshr(lhs, rhs) + | Bvashr(lhs, rhs) + | Concat(lhs, rhs) + | FPBinary(_, lhs, rhs) => { + let lhs_uses = exp_uses(lhs); + let rhs_uses = exp_uses(rhs); + &lhs_uses | &rhs_uses + } + Ite(cond, then_exp, else_exp) => { + let cond_uses = exp_uses(cond); + let then_uses = exp_uses(then_exp); + let else_uses = exp_uses(else_exp); + let uses = &cond_uses | &then_uses; + &uses | &else_uses + } + //App(f, args) => { + // uses.insert(*f, uses.get(f).unwrap_or(&0) + 1); + // for arg in args { + // uses_in_exp(uses, arg); + // } + //} + //Select(array, index) => { + // uses_in_exp(uses, array); + // uses_in_exp(uses, index) + //} + //Store(array, index, val) => { + // uses_in_exp(uses, array); + // uses_in_exp(uses, index); + // uses_in_exp(uses, val) + //} + //Distinct(exps) => { + // for exp in exps { + // uses_in_exp(uses, exp); + // } + //} + //FPRoundingUnary(_, rm, exp) => { + // uses_in_exp(uses, rm); + // uses_in_exp(uses, exp); + //} + //FPRoundingBinary(_, rm, lhs, rhs) => { + // uses_in_exp(uses, rm); + // uses_in_exp(uses, lhs); + // uses_in_exp(uses, rhs) + //} + //FPfma(rm, x, y, z) => { + // uses_in_exp(uses, rm); + // uses_in_exp(uses, x); + // uses_in_exp(uses, y); + // uses_in_exp(uses, z) + //} + _ => todo!("not yet implemented expression: {:?}", exp), + } +} + +fn smt_def_uses(def: &smtlib::Def) -> HashSet { + match def { + // DeclareConst(Sym, Ty), + // DeclareFun(Sym, Vec, Ty), + smtlib::Def::DefineConst(_, exp) => exp_uses(&exp), + // DefineEnum(Name, usize), + // Assert(Exp), + _ => HashSet::new(), + } +} + +fn val_uses(val: &Val) -> HashSet { + // See: simplify::uses_in_value + use Val::*; + match val { + Symbolic(sym) => HashSet::from([*sym]), + // MixedBits(segments) => segments.iter().for_each(|segment| match segment { + // BitsSegment::Symbolic(v) => { + // uses.insert(*v, uses.get(v).unwrap_or(&0) + 1); + // } + // BitsSegment::Concrete(_) => (), + // }), + I64(_) | I128(_) | Bool(_) | Bits(_) | Enum(_) | String(_) | Unit | Ref(_) | Poison => { + HashSet::new() + } + // List(vals) | Vector(vals) => vals.iter().for_each(|val| uses_in_value(uses, val)), + Struct(fields) => fields + .iter() + .map(|(_, val)| val_uses(val)) + .fold(HashSet::new(), |acc, uses| &acc | &uses), + // Ctor(_, val) => uses_in_value(uses, val), + // SymbolicCtor(v, possibilities) => { + // uses.insert(*v, uses.get(v).unwrap_or(&0) + 1); + // possibilities + // .iter() + // .for_each(|(_, val)| uses_in_value(uses, val)) + // } + _ => todo!("not yet implemented value: {:?}", val), + } +} + +fn uses(event: &Event) -> HashSet { + match event { + Event::Smt(def, _, _) => smt_def_uses(&def), + Event::WriteReg(_, _, val) => val_uses(val), + _ => HashSet::new(), + } +} + +fn tree_shake(events: &Vec>) -> Vec> { + // Definitions. + let defn_idx = defns(events); + + // Work list: populate with register writes. + let mut work_list = Vec::new(); + let mut live = HashSet::new(); + for (i, event) in events.iter().enumerate() { + match event { + Event::WriteReg(_, _, val) => val_uses(val).iter().for_each(|sym| { + // Mark live. + live.insert(i); + + // Push the variable to be visited. + let d = defn_idx[&sym]; + live.insert(d); + work_list.push(d); + }), + _ => continue, + }; + } + + // Process. + while !work_list.is_empty() { + let i = work_list.pop().unwrap(); + assert!(live.contains(&i), "visited events should be live"); + let event = &events[i]; + + // Mark uses live. + for u in uses(&event) { + // Lookup definition of this dependency. + assert!(defn_idx.contains_key(&u), "no definition for {:?}", u); + let ui = defn_idx[&u]; + if live.contains(&ui) { + continue; + } + + live.insert(ui); + work_list.push(ui); + } + } + + // Filter down to live events. + let mut events: Vec<_> = events + .iter() + .enumerate() + .filter_map(|(i, event)| if live.contains(&i) { Some(event) } else { None }) + .cloned() + .collect(); + + // Simplify pass. + events.reverse(); + simplify::propagate_forwards_used_once(&mut events); + events.reverse(); + + events +} + +fn write_events<'ir, B: BV>( + events: &Vec>, + iarch: &'ir Initialized<'ir, B>, +) -> anyhow::Result<()> { + // Print. + let stdout = std::io::stdout(); + let mut handle = BufWriter::with_capacity(5 * usize::pow(2, 20), stdout.lock()); + let write_opts = WriteOpts::default(); + simplify::write_events_with_opts(&mut handle, &events, &iarch.shared_state, &write_opts) + .unwrap(); + handle.flush().unwrap(); + + Ok(()) +} + +#[derive(Clone)] +struct SpecConfig { + term: String, + args: Vec, + reg_read: HashMap, + reg_write: HashMap, + var_prefix: String, +} + +struct SpecConverter<'ir, B: BV> { + cfg: SpecConfig, + iarch: &'ir Initialized<'ir, B>, + + // Specification object under construction. + spec: Spec, + + // Keep track of registers read and written in the trace. + reg_reads: HashSet, + reg_writes: HashSet, + + // Types of SMT variables and functions. Required for ISLA type inference. + ty: HashMap, + funty: HashMap, smtlib::Ty)>, +} + +impl<'ir, B: BV> SpecConverter<'ir, B> { + fn new(cfg: SpecConfig, iarch: &'ir Initialized<'ir, B>) -> Self { + Self { + cfg: cfg.clone(), + iarch, + spec: Spec { + term: spec_ident(cfg.term), + args: cfg.args.iter().cloned().map(spec_ident).collect(), + requires: vec![], + provides: vec![], + }, + reg_reads: HashSet::new(), + reg_writes: HashSet::new(), + ty: HashMap::new(), + funty: HashMap::new(), + } + } + + fn convert(&mut self, events: &Vec>) -> anyhow::Result { + for event in events { + if let Some(exp) = self.event(event)? { + self.spec.provides.push(exp); + } + } + Ok(self.spec.clone()) + } + + fn event(&mut self, event: &Event) -> anyhow::Result> { + match event { + Event::Smt(def, attr, ..) if !attr.is_uninteresting() => self.smt(def), + + Event::ReadReg(name, acc, val) => { + if !acc.is_empty() { + anyhow::bail!("register read accessors unimplemented"); + } + + if let Val::Symbolic(sym) = val { + self.read_reg(name, sym) + } else { + anyhow::bail!("non-symbolic register reads are unimplemented"); + } + } + + Event::WriteReg(name, acc, val) => { + if !acc.is_empty() { + anyhow::bail!("register write accessors unimplemented"); + } + + if let Val::Symbolic(sym) = val { + self.write_reg(name, sym) + } else { + anyhow::bail!("non-symbolic register writes are unimplemented"); + } + } + + _ => anyhow::bail!("unsupported event type: {:?}", event), + } + } + + fn read_reg(&mut self, name: &Name, sym: &Sym) -> anyhow::Result> { + // Map to a string name. + let reg = self.lookup_name(name); + + // Expect to find a configured mapping for this register read. + let mapped_var = match self.cfg.reg_read.get(®) { + Some(v) => v.clone(), + None => anyhow::bail!("no mapping for read of register {}", reg), + }; + + // Expect register to be read only once. + if self.reg_reads.contains(®) { + anyhow::bail!("multiple reads of register {}", reg); + } + self.reg_reads.insert(reg.clone()); + + // Emit expression binding the ISLA variable to mapped ISLE term. + Ok(Some(SpecExpr::Op { + op: SpecOp::Eq, + args: vec![spec_var(mapped_var), self.sym(sym)], + pos: Pos::default(), + })) + } + + fn write_reg(&mut self, name: &Name, sym: &Sym) -> anyhow::Result> { + // Map to a string name. + let reg = self.lookup_name(name); + + // Expect to find a configured mapping for this register write. + let mapped_var = match self.cfg.reg_write.get(®) { + Some(v) => v.clone(), + None => anyhow::bail!("no mapping for write of register {}", reg), + }; + + // Expect register to be written only once. + if self.reg_writes.contains(®) { + anyhow::bail!("multiple writes of register {}", reg); + } + self.reg_writes.insert(reg.clone()); + + // Emit expression binding the ISLA variable to mapped ISLE term. + Ok(Some(SpecExpr::Op { + op: SpecOp::Eq, + args: vec![spec_var(mapped_var), self.sym(sym)], + pos: Pos::default(), + })) + } + + fn smt(&mut self, def: &smtlib::Def) -> anyhow::Result> { + match def { + smtlib::Def::DefineConst(v, exp) => { + let ty = self.infer(exp).expect("SMT expression was badly-typed"); + self.ty.insert(*v, ty.clone()); + + Ok(Some(SpecExpr::Op { + op: SpecOp::Eq, + args: vec![self.sym(v), self.exp(exp)], + pos: Pos::default(), + })) + } + + smtlib::Def::DeclareConst(v, ty) => { + self.ty.insert(*v, ty.clone()); + Ok(None) + } + + smtlib::Def::DeclareFun(v, params, ret) => { + self.funty.insert(*v, (params.clone(), ret.clone())); + Ok(None) + } + + smtlib::Def::DefineEnum(..) => Ok(None), + + _ => anyhow::bail!("unsupported smt def: {:?}", def), + } + } + + fn exp(&self, exp: &smtlib::Exp) -> SpecExpr { + use smtlib::Exp::*; + match exp { + Var(v) => self.sym(v), + Bits(bits) => spec_bits(bits), + Bits64(bv) => spec_const_bit_vector( + bv.lower_u64().try_into().unwrap(), + bv.len().try_into().unwrap(), + ), + // Enum(EnumMember), + Bool(b) => spec_const_bool(*b), + // Neq(Box>, Box>), + Not(x) | Bvnot(x) => spec_unary(exp_spec_op(exp), self.exp(x)), + + // Bvnot(Box>), + // Bvnand(Box>, Box>), + // Bvnor(Box>, Box>), + // Bvxnor(Box>, Box>), + // Bvneg(Box>), + Eq(lhs, rhs) + | And(lhs, rhs) + | Or(lhs, rhs) + | Bvand(lhs, rhs) + | Bvor(lhs, rhs) + | Bvxor(lhs, rhs) + | Bvadd(lhs, rhs) + | Bvsub(lhs, rhs) + | Bvmul(lhs, rhs) + | Bvshl(lhs, rhs) + | Bvlshr(lhs, rhs) + | Concat(lhs, rhs) => spec_binary(exp_spec_op(exp), self.exp(lhs), self.exp(rhs)), + + // Bvudiv(Box>, Box>), + // Bvsdiv(Box>, Box>), + // Bvurem(Box>, Box>), + // Bvsrem(Box>, Box>), + // Bvsmod(Box>, Box>), + // Bvult(Box>, Box>), + // Bvslt(Box>, Box>), + // Bvule(Box>, Box>), + // Bvsle(Box>, Box>), + // Bvuge(Box>, Box>), + // Bvsge(Box>, Box>), + // Bvugt(Box>, Box>), + // Bvsgt(Box>, Box>), + Extract(i, j, exp) => spec_ternary( + SpecOp::Extract, + spec_const_int(*i), + spec_const_int(*j), + self.exp(exp), + ), + + ZeroExtend(n, x) | SignExtend(n, x) => match self.infer(x).unwrap() { + smtlib::Ty::BitVec(w) => { + spec_binary(exp_spec_op(exp), spec_const_int(n + w), self.exp(x)) + } + _ => panic!("extension applies to bitvector types"), + }, + + // Bvlshr(Box>, Box>), + // Bvashr(Box>, Box>), + Ite(c, t, e) => spec_ternary(SpecOp::If, self.exp(c), self.exp(t), self.exp(e)), + + // App(Sym, Vec>), + // Select(Box>, Box>), + // Store(Box>, Box>, Box>), + // Distinct(Vec>), + // FPConstant(FPConstant, u32, u32), + // FPRoundingMode(FPRoundingMode), + // FPUnary(FPUnary, Box>), + // FPRoundingUnary(FPRoundingUnary, Box>, Box>), + // FPBinary(FPBinary, Box>, Box>), + // FPRoundingBinary(FPRoundingBinary, Box>, Box>, Box>), + // FPfma(Box>, Box>, Box>, Box>), + _ => todo!("expression: {:?}", exp), + } + } + + fn sym(&self, s: &Sym) -> SpecExpr { + spec_var(format!("{}{}", self.cfg.var_prefix, s)) + } + + fn infer(&self, exp: &smtlib::Exp) -> Option { + exp.infer(&self.ty, &self.funty) + } + + fn lookup_name(&self, name: &Name) -> String { + zencode::decode(self.iarch.shared_state.symtab.to_str(name.clone())) + } +} + +fn exp_spec_op(exp: &smtlib::Exp) -> SpecOp { + use smtlib::Exp::*; + match exp { + // Bits(Vec), + // Bits64(B64), + // Enum(EnumMember), + // Bool(bool), + Eq(..) => SpecOp::Eq, + // Neq(Box>, Box>), + And(..) => SpecOp::And, + Or(..) => SpecOp::Or, + Not(..) => SpecOp::Not, + Bvnot(..) => SpecOp::BVNot, + Bvand(..) => SpecOp::BVAnd, + Bvor(..) => SpecOp::BVOr, + Bvxor(..) => SpecOp::BVXor, + // Bvnand(Box>, Box>), + // Bvnor(Box>, Box>), + // Bvxnor(Box>, Box>), + // Bvneg(Box>), + Bvadd(..) => SpecOp::BVAdd, + Bvsub(..) => SpecOp::BVSub, + Bvmul(..) => SpecOp::BVMul, + // Bvudiv(Box>, Box>), + // Bvsdiv(Box>, Box>), + // Bvurem(Box>, Box>), + // Bvsrem(Box>, Box>), + // Bvsmod(Box>, Box>), + // Bvult(Box>, Box>), + // Bvslt(Box>, Box>), + // Bvule(Box>, Box>), + // Bvsle(Box>, Box>), + // Bvuge(Box>, Box>), + // Bvsge(Box>, Box>), + // Bvugt(Box>, Box>), + // Bvsgt(Box>, Box>), + ZeroExtend(..) => SpecOp::ZeroExt, + SignExtend(..) => SpecOp::SignExt, + Bvshl(..) => SpecOp::BVShl, + Bvlshr(..) => SpecOp::BVLshr, + // Bvashr(Box>, Box>), + Concat(..) => SpecOp::Concat, + // Ite(Box>, Box>, Box>), + // App(Sym, Vec>), + // Select(Box>, Box>), + // Store(Box>, Box>, Box>), + // Distinct(Vec>), + // FPConstant(FPConstant, u32, u32), + // FPRoundingMode(FPRoundingMode), + // FPUnary(FPUnary, Box>), + // FPRoundingUnary(FPRoundingUnary, Box>, Box>), + // FPBinary(FPBinary, Box>, Box>), + // FPRoundingBinary(FPRoundingBinary, Box>, Box>, Box>), + // FPfma(Box>, Box>, Box>, Box>), + _ => todo!("spec op: {:?}", exp), + } +} + +fn spec_const_int(x: I) -> SpecExpr +where + i128: From, +{ + SpecExpr::ConstInt { + val: x.try_into().unwrap(), + pos: Pos::default(), + } +} + +fn spec_const_bool(b: bool) -> SpecExpr { + SpecExpr::ConstBool { + val: if b { 1 } else { 0 }, + pos: Pos::default(), + } +} + +fn spec_const_bit_vector(val: i128, width: i8) -> SpecExpr { + assert!(width >= 0); + SpecExpr::ConstBitVec { + val, + width, + pos: Pos::default(), + } +} + +fn spec_bits(bits: &[bool]) -> SpecExpr { + // TODO(mbm): verify endianness assumption about Vec and test multi-chunk case + bits.chunks(64) + .map(|chunk| { + let mut val: i128 = 0; + for (i, bit) in chunk.iter().enumerate() { + if *bit { + val |= 1 << i; + } + } + spec_const_bit_vector(val, 64) + }) + .rev() + .reduce(|acc, bv| spec_binary(SpecOp::Concat, acc, bv)) + .unwrap() +} + +fn spec_unary(op: SpecOp, x: SpecExpr) -> SpecExpr { + SpecExpr::Op { + op, + args: vec![x], + pos: Pos::default(), + } +} + +fn spec_binary(op: SpecOp, x: SpecExpr, y: SpecExpr) -> SpecExpr { + SpecExpr::Op { + op, + args: vec![x, y], + pos: Pos::default(), + } +} + +fn spec_ternary(op: SpecOp, x: SpecExpr, y: SpecExpr, z: SpecExpr) -> SpecExpr { + SpecExpr::Op { + op, + args: vec![x, y, z], + pos: Pos::default(), + } +} + +fn spec_var(id: String) -> SpecExpr { + SpecExpr::Var { + var: spec_ident(id), + pos: Pos::default(), + } +} + +fn spec_ident(id: String) -> Ident { + Ident(id, Pos::default()) +} From 92c6ffd94eef520e8680be7202597421fa8c1083 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Thu, 11 Jan 2024 22:44:19 -0500 Subject: [PATCH 48/73] expend spec config to produce a real spec --- .../isle/veri/veri_engine/src/bin/isaspec.rs | 51 ++++++++++++------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs b/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs index 65d3f1860e2c..c35d4ab930f4 100644 --- a/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs +++ b/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs @@ -62,15 +62,32 @@ fn main() -> anyhow::Result<()> { rm: xreg(6), }; let cfg = SpecConfig { + // Spec signature. term: "MInst.AluRRR".to_string(), args: ["alu_op", "size", "rd", "rn", "rm"] .map(String::from) .to_vec(), + + // Requires. + require: vec![ + spec_eq( + spec_var("alu_op".to_string()), + spec_enum("ALUOp".to_string(), "Add".to_string()), + ), + spec_eq( + spec_var("size".to_string()), + spec_enum("OperandSize".to_string(), "Size64".to_string()), + ), + ], + + // Register read/write bindings. reg_read: HashMap::from([ ("R5".to_string(), "rn".to_string()), ("R6".to_string(), "rm".to_string()), ]), reg_write: HashMap::from([("R4".to_string(), "rd".to_string())]), + + // ISLA intermediate variable naming. var_prefix: "v".to_string(), }; @@ -86,6 +103,7 @@ fn main() -> anyhow::Result<()> { println!("inst = {inst:?}"); println!("opcode = {opcode:08x}"); println!("asm = {asm}"); + println!("config = {cfg:?}"); println!(""); // ISLA trace. @@ -473,10 +491,11 @@ fn write_events<'ir, B: BV>( Ok(()) } -#[derive(Clone)] +#[derive(Debug, Clone)] struct SpecConfig { term: String, args: Vec, + require: Vec, reg_read: HashMap, reg_write: HashMap, var_prefix: String, @@ -506,7 +525,7 @@ impl<'ir, B: BV> SpecConverter<'ir, B> { spec: Spec { term: spec_ident(cfg.term), args: cfg.args.iter().cloned().map(spec_ident).collect(), - requires: vec![], + requires: cfg.require, provides: vec![], }, reg_reads: HashSet::new(), @@ -574,11 +593,7 @@ impl<'ir, B: BV> SpecConverter<'ir, B> { self.reg_reads.insert(reg.clone()); // Emit expression binding the ISLA variable to mapped ISLE term. - Ok(Some(SpecExpr::Op { - op: SpecOp::Eq, - args: vec![spec_var(mapped_var), self.sym(sym)], - pos: Pos::default(), - })) + Ok(Some(spec_eq(spec_var(mapped_var), self.sym(sym)))) } fn write_reg(&mut self, name: &Name, sym: &Sym) -> anyhow::Result> { @@ -598,11 +613,7 @@ impl<'ir, B: BV> SpecConverter<'ir, B> { self.reg_writes.insert(reg.clone()); // Emit expression binding the ISLA variable to mapped ISLE term. - Ok(Some(SpecExpr::Op { - op: SpecOp::Eq, - args: vec![spec_var(mapped_var), self.sym(sym)], - pos: Pos::default(), - })) + Ok(Some(spec_eq(spec_var(mapped_var), self.sym(sym)))) } fn smt(&mut self, def: &smtlib::Def) -> anyhow::Result> { @@ -611,11 +622,7 @@ impl<'ir, B: BV> SpecConverter<'ir, B> { let ty = self.infer(exp).expect("SMT expression was badly-typed"); self.ty.insert(*v, ty.clone()); - Ok(Some(SpecExpr::Op { - op: SpecOp::Eq, - args: vec![self.sym(v), self.exp(exp)], - pos: Pos::default(), - })) + Ok(Some(spec_eq(self.sym(v), self.exp(exp)))) } smtlib::Def::DeclareConst(v, ty) => { @@ -842,6 +849,10 @@ fn spec_binary(op: SpecOp, x: SpecExpr, y: SpecExpr) -> SpecExpr { } } +fn spec_eq(x: SpecExpr, y: SpecExpr) -> SpecExpr { + spec_binary(SpecOp::Eq, x, y) +} + fn spec_ternary(op: SpecOp, x: SpecExpr, y: SpecExpr, z: SpecExpr) -> SpecExpr { SpecExpr::Op { op, @@ -850,6 +861,12 @@ fn spec_ternary(op: SpecOp, x: SpecExpr, y: SpecExpr, z: SpecExpr) -> SpecExpr { } } +fn spec_enum(name: String, variant: String) -> SpecExpr { + SpecExpr::Enum { + name: spec_ident(format!("{}.{}", name, variant)), + } +} + fn spec_var(id: String) -> SpecExpr { SpecExpr::Var { var: spec_ident(id), From 8e3f5cf1d0a8ed0e582da397e5854ead7315f8a7 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Wed, 17 Jan 2024 13:17:29 -0500 Subject: [PATCH 49/73] veriisle: specfunc experiment for executing single spec functions --- .../isle/veri/veri_engine/src/bin/specfunc.rs | 173 ++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 cranelift/isle/veri/veri_engine/src/bin/specfunc.rs diff --git a/cranelift/isle/veri/veri_engine/src/bin/specfunc.rs b/cranelift/isle/veri/veri_engine/src/bin/specfunc.rs new file mode 100644 index 000000000000..1aa4349fa528 --- /dev/null +++ b/cranelift/isle/veri/veri_engine/src/bin/specfunc.rs @@ -0,0 +1,173 @@ +use crossbeam::queue::SegQueue; +use isla::opts; +use isla_lib::bitvector::{b64::B64, BV}; +use isla_lib::error::IslaError; +use isla_lib::executor::{self, LocalFrame, TaskState}; +use isla_lib::init::{initialize_architecture, Initialized}; +use isla_lib::ir::{AssertionMode, Val}; +use isla_lib::memory::Memory; +use isla_lib::simplify::{self, WriteOpts}; +use isla_lib::smt::{self, Checkpoint, Event, Solver}; +use isla_lib::zencode; +use sha2::{Digest, Sha256}; +use std::io::prelude::*; +use std::io::BufWriter; +use std::path::PathBuf; +use std::sync::Arc; + +fn main() -> anyhow::Result<()> { + // Command-line options. + let opts = opts::common_opts(); + + // Build ISLA architecture. + let mut hasher = Sha256::new(); + let (matches, arch) = opts::parse::(&mut hasher, &opts); + let opts::CommonOpts { + num_threads: _, + mut arch, + symtab, + type_info, + isa_config, + source_path: _, + } = opts::parse_with_arch(&mut hasher, &opts, &matches, &arch); + let use_model_reg_init = true; + let iarch = initialize_architecture( + &mut arch, + symtab, + type_info, + &isa_config, + AssertionMode::Optimistic, + use_model_reg_init, + ); + + // ISLA trace. + let paths = trace_execute_function(&iarch)?; + + // Dump. + for events in paths { + write_events_to_stdout(&events, &iarch)?; + } + + Ok(()) +} + +fn trace_execute_function<'ir, B: BV>( + iarch: &'ir Initialized<'ir, B>, +) -> anyhow::Result>>> { + let shared_state = &&iarch.shared_state; + + let initial_checkpoint = Checkpoint::new(); + let solver_cfg = smt::Config::new(); + let solver_ctx = smt::Context::new(solver_cfg); + let mut solver = Solver::from_checkpoint(&solver_ctx, initial_checkpoint); + let checkpoint = smt::checkpoint(&mut solver); + + // val execute_aarch64_instrs_integer_conditional_compare_register : forall 'datasize 'm 'n ('sub_op : Bool), + // (0 <= 'n & 'n <= 31 & 0 <= 'm & 'm <= 31 & 'datasize in {32, 64}). + // (bits(4), int('datasize), bits(4), int('m), int('n), bool('sub_op)) -> unit + // function execute_aarch64_instrs_integer_conditional_compare_register (condition, datasize, flags__arg, m, n, sub_op) = { + + let execute_function = + zencode::encode("execute_aarch64_instrs_integer_conditional_compare_register"); + // condition: bits(4) + let condition = Val::Bits(B::new(7, 4)); + // datasize: int('datasize) + let datasize = Val::I64(64); + // flags__arg + let flags_arg = Val::Bits(B::new(3, 4)); + // m + let rm = Val::I64(3); + // n + let rn = Val::I64(4); + // sub_op + let sub_op = Val::Bool(false); + + let function_id = shared_state.symtab.lookup(&execute_function); + let (args, ret_ty, instrs) = shared_state.functions.get(&function_id).unwrap(); + let memory = Memory::new(); + let task_state = TaskState::::new(); + let task = LocalFrame::new( + function_id, + args, + ret_ty, + Some(&[condition, datasize, flags_arg, rm, rn, sub_op]), + instrs, + ) + .add_lets(&iarch.lets) + .add_regs(&iarch.regs) + .set_memory(memory) + .task_with_checkpoint(0, &task_state, checkpoint); + + let num_threads = 1; + let queue = Arc::new(SegQueue::new()); + executor::start_multi( + num_threads, + None, + vec![task], + shared_state, + queue.clone(), + &executor::trace_collector, + ); + + let mut paths = Vec::new(); + loop { + match queue.pop() { + Some(Ok((_, mut events))) => { + simplify::hide_initialization(&mut events); + simplify::remove_extra_register_fields(&mut events); + simplify::remove_repeated_register_reads(&mut events); + simplify::remove_unused_register_assumptions(&mut events); + simplify::remove_unused(&mut events); + simplify::propagate_forwards_used_once(&mut events); + simplify::commute_extract(&mut events); + simplify::eval(&mut events); + + let events: Vec> = events.drain(..).rev().collect(); + paths.push(events); + } + + // Error during execution + Some(Err(err)) => { + let msg = format!("{}", err); + eprintln!( + "{}", + err.source_loc().message::( + None, + shared_state.symtab.files(), + &msg, + true, + true + ) + ); + anyhow::bail!("{}", err); + } + // Empty queue + None => break, + } + } + + Ok(paths) +} + +/// Write ISLA trace events to stdout. +fn write_events_to_stdout<'ir, B: BV>( + events: &Vec>, + iarch: &'ir Initialized<'ir, B>, +) -> anyhow::Result<()> { + let stdout = std::io::stdout().lock(); + write_events(events, iarch, stdout) +} + +fn write_events<'ir, B: BV>( + events: &Vec>, + iarch: &'ir Initialized<'ir, B>, + w: impl Sized + Write, +) -> anyhow::Result<()> { + let mut handle = BufWriter::with_capacity(5 * usize::pow(2, 20), w); + let write_opts = WriteOpts::default(); + simplify::write_events_with_opts(&mut handle, &events, &iarch.shared_state, &write_opts) + .unwrap(); + handle.flush().unwrap(); + + Ok(()) +} From 31e6ec763eacb07794806fecb7f0025b34ecc23b Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Wed, 17 Jan 2024 14:03:56 -0500 Subject: [PATCH 50/73] veriisle: exec add function --- .../isle/veri/veri_engine/src/bin/specfunc.rs | 45 ++++++++++++++----- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/cranelift/isle/veri/veri_engine/src/bin/specfunc.rs b/cranelift/isle/veri/veri_engine/src/bin/specfunc.rs index 1aa4349fa528..608e2fab5f5f 100644 --- a/cranelift/isle/veri/veri_engine/src/bin/specfunc.rs +++ b/cranelift/isle/veri/veri_engine/src/bin/specfunc.rs @@ -62,23 +62,44 @@ fn trace_execute_function<'ir, B: BV>( let mut solver = Solver::from_checkpoint(&solver_ctx, initial_checkpoint); let checkpoint = smt::checkpoint(&mut solver); - // val execute_aarch64_instrs_integer_conditional_compare_register : forall 'datasize 'm 'n ('sub_op : Bool), - // (0 <= 'n & 'n <= 31 & 0 <= 'm & 'm <= 31 & 'datasize in {32, 64}). - // (bits(4), int('datasize), bits(4), int('m), int('n), bool('sub_op)) -> unit - // function execute_aarch64_instrs_integer_conditional_compare_register (condition, datasize, flags__arg, m, n, sub_op) = { + // // val execute_aarch64_instrs_integer_conditional_compare_register : forall 'datasize 'm 'n ('sub_op : Bool), + // // (0 <= 'n & 'n <= 31 & 0 <= 'm & 'm <= 31 & 'datasize in {32, 64}). + // // (bits(4), int('datasize), bits(4), int('m), int('n), bool('sub_op)) -> unit + // // function execute_aarch64_instrs_integer_conditional_compare_register (condition, datasize, flags__arg, m, n, sub_op) = { + + // let execute_function = + // zencode::encode("execute_aarch64_instrs_integer_conditional_compare_register"); + // // condition: bits(4) + // let condition = Val::Bits(B::new(7, 4)); + // // datasize: int('datasize) + // let datasize = Val::I64(64); + // // flags__arg + // let flags_arg = Val::Bits(B::new(3, 4)); + // // m + // let rm = Val::I64(3); + // // n + // let rn = Val::I64(4); + // // sub_op + // let sub_op = Val::Bool(false); + + // val execute_aarch64_instrs_integer_arithmetic_add_sub_carry : forall 'd 'datasize 'm 'n ('setflags : Bool) ('sub_op : Bool), + // (0 <= 'n & 'n <= 31 & 0 <= 'm & 'm <= 31 & 'datasize in {32, 64} & 0 <= 'd & 'd <= 31). + // (int('d), int('datasize), int('m), int('n), bool('setflags), bool('sub_op)) -> unit + // + // function execute_aarch64_instrs_integer_arithmetic_add_sub_carry (d, datasize, m, n, setflags, sub_op) = { let execute_function = - zencode::encode("execute_aarch64_instrs_integer_conditional_compare_register"); - // condition: bits(4) - let condition = Val::Bits(B::new(7, 4)); - // datasize: int('datasize) + zencode::encode("execute_aarch64_instrs_integer_arithmetic_add_sub_carry"); + // d + let rd = Val::I64(2); + // datasize let datasize = Val::I64(64); - // flags__arg - let flags_arg = Val::Bits(B::new(3, 4)); // m let rm = Val::I64(3); // n let rn = Val::I64(4); + // setflags + let setflags = Val::Bool(true); // sub_op let sub_op = Val::Bool(false); @@ -90,7 +111,7 @@ fn trace_execute_function<'ir, B: BV>( function_id, args, ret_ty, - Some(&[condition, datasize, flags_arg, rm, rn, sub_op]), + Some(&[rd, datasize, rm, rn, setflags, sub_op]), instrs, ) .add_lets(&iarch.lets) @@ -113,7 +134,7 @@ fn trace_execute_function<'ir, B: BV>( loop { match queue.pop() { Some(Ok((_, mut events))) => { - simplify::hide_initialization(&mut events); + //simplify::hide_initialization(&mut events); simplify::remove_extra_register_fields(&mut events); simplify::remove_repeated_register_reads(&mut events); simplify::remove_unused_register_assumptions(&mut events); From f26b4868bacb929a2267704011132756b6b23785 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Thu, 25 Jan 2024 23:31:30 -0500 Subject: [PATCH 51/73] isaspec: provide cases --- cranelift/isle/isle/src/ast.rs | 1 + cranelift/isle/isle/src/printer.rs | 1 + .../isle/veri/veri_engine/src/bin/isaspec.rs | 299 ++++++++++++------ 3 files changed, 205 insertions(+), 96 deletions(-) diff --git a/cranelift/isle/isle/src/ast.rs b/cranelift/isle/isle/src/ast.rs index 194d9dd8a13d..88bd92d260d5 100644 --- a/cranelift/isle/isle/src/ast.rs +++ b/cranelift/isle/isle/src/ast.rs @@ -142,6 +142,7 @@ pub enum SpecOp { And, Or, Not, + Imp, // Integer comparisons Lt, diff --git a/cranelift/isle/isle/src/printer.rs b/cranelift/isle/isle/src/printer.rs index 2af62a370959..231eb21eee67 100644 --- a/cranelift/isle/isle/src/printer.rs +++ b/cranelift/isle/isle/src/printer.rs @@ -227,6 +227,7 @@ impl Printable for SpecOp { SpecOp::And => "and", SpecOp::Not => "not", SpecOp::Or => "or", + SpecOp::Imp => "=>", SpecOp::Lte => "<=", SpecOp::Lt => "<", SpecOp::Gte => ">=", diff --git a/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs b/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs index c35d4ab930f4..b44f0ccc52ae 100644 --- a/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs +++ b/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs @@ -19,6 +19,7 @@ use isla_lib::simplify::{self, WriteOpts}; use isla_lib::smt::smtlib; use isla_lib::smt::{self, Checkpoint, Event, Solver, Sym}; use isla_lib::zencode; +use itertools::Itertools; use sha2::{Digest, Sha256}; use std::collections::{HashMap, HashSet}; use std::io::prelude::*; @@ -30,7 +31,6 @@ fn main() -> anyhow::Result<()> { // Command-line options. let mut opts = opts::common_opts(); opts.optflag("", "filter", "filter relevant events from the trace"); - //opts.optflag("", "spec", "convert traces to veri-isle specs"); // Build ISLA architecture. let mut hasher = Sha256::new(); @@ -53,80 +53,70 @@ fn main() -> anyhow::Result<()> { use_model_reg_init, ); - // Assemble and trace instructions. - let inst = Inst::AluRRR { - alu_op: ALUOp::Add, - size: OperandSize::Size64, - rd: writable_xreg(4), - rn: xreg(5), - rm: xreg(6), - }; - let cfg = SpecConfig { + // Spec configuration. + let cfg = define(); + + // Generate spec. + let mut spec_converter = SpecConverter::new(cfg, &iarch); + let spec = spec_converter.generate()?; + printer::dump(&spec)?; + + // // Assemble. + // let opcodes = opcodes(&inst); + // assert_eq!(opcodes.len(), 1); + // let opcode = opcodes[0]; + + // // Show assembly. + // let asm = inst.print_with_state(&mut EmitState::default(), &mut AllocationConsumer::new(&[])); + + // println!("--------------------------------------------------"); + // println!("inst = {inst:?}"); + // println!("opcode = {opcode:08x}"); + // println!("asm = {asm}"); + // println!("config = {cfg:?}"); + // println!(""); + + Ok(()) +} + +/// Define specificiations to generate. +fn define() -> SpecConfig { + SpecConfig { // Spec signature. term: "MInst.AluRRR".to_string(), args: ["alu_op", "size", "rd", "rn", "rm"] .map(String::from) .to_vec(), - // Requires. - require: vec![ - spec_eq( - spec_var("alu_op".to_string()), - spec_enum("ALUOp".to_string(), "Add".to_string()), - ), - spec_eq( - spec_var("size".to_string()), - spec_enum("OperandSize".to_string(), "Size64".to_string()), - ), - ], - - // Register read/write bindings. - reg_read: HashMap::from([ - ("R5".to_string(), "rn".to_string()), - ("R6".to_string(), "rm".to_string()), - ]), - reg_write: HashMap::from([("R4".to_string(), "rd".to_string())]), - - // ISLA intermediate variable naming. - var_prefix: "v".to_string(), - }; - - // Assemble. - let opcodes = opcodes(&inst); - assert_eq!(opcodes.len(), 1); - let opcode = opcodes[0]; - - // Show assembly. - let asm = inst.print_with_state(&mut EmitState::default(), &mut AllocationConsumer::new(&[])); - - println!("--------------------------------------------------"); - println!("inst = {inst:?}"); - println!("opcode = {opcode:08x}"); - println!("asm = {asm}"); - println!("config = {cfg:?}"); - println!(""); - - // ISLA trace. - let paths = trace_opcode(opcode, &iarch)?; - assert_eq!(paths.len(), 1); - let events = &paths[0]; - - // Dump. - let events = if matches.opt_present("filter") { - tree_shake(&events) - } else { - events.clone() - }; - write_events(&events, &iarch)?; - - // Generate spec. - let mut spec_converter = SpecConverter::new(cfg, &iarch); - match spec_converter.convert(&events) { - Ok(spec) => printer::dump(&spec)?, - Err(err) => println!("spec conversion failed: {}", err), - }; + cases: vec![InstConfig { + inst: Inst::AluRRR { + alu_op: ALUOp::Add, + size: OperandSize::Size64, + rd: writable_xreg(4), + rn: xreg(5), + rm: xreg(6), + }, - Ok(()) + // Requires. + require: vec![ + spec_eq( + spec_var("alu_op".to_string()), + spec_enum("ALUOp".to_string(), "Add".to_string()), + ), + spec_eq( + spec_var("size".to_string()), + spec_enum("OperandSize".to_string(), "Size64".to_string()), + ), + ], + + // Register read/write bindings. + reg_read: HashMap::from([ + ("R5".to_string(), "rn".to_string()), + ("R6".to_string(), "rm".to_string()), + ]), + reg_write: HashMap::from([("R4".to_string(), "rd".to_string())]), + }], + } } // struct SpecBuilder<'ir, B: BV> { @@ -191,7 +181,7 @@ fn trace_opcode<'ir, B: BV>( let opcode_val = Val::Bits(B::from_u32(opcode)); - let footprint_function = "zisla_footprint_no_init"; + let footprint_function = zencode::encode("isla_footprint_no_init"); let function_id = shared_state.symtab.lookup(&footprint_function); let (args, ret_ty, instrs) = shared_state.functions.get(&function_id).unwrap(); let memory = Memory::new(); @@ -491,22 +481,118 @@ fn write_events<'ir, B: BV>( Ok(()) } +#[derive(Clone)] +struct Conditions { + requires: Vec, + provides: Vec, +} + +impl Conditions { + fn new() -> Self { + Self { + requires: Vec::new(), + provides: Vec::new(), + } + } + + fn merge(cs: Vec) -> Self { + match cs.len() { + 0 => Self::new(), + 1 => cs[0].clone(), + _ => Self { + requires: vec![spec_or( + cs.iter().map(|c| spec_and(c.requires.clone())).collect(), + )], + provides: cs + .iter() + .map(|c| { + spec_binary( + SpecOp::Imp, + spec_and(c.requires.clone()), + spec_and(c.provides.clone()), + ) + }) + .collect(), + }, + } + } +} + #[derive(Debug, Clone)] struct SpecConfig { term: String, args: Vec, + cases: Vec, +} + +#[derive(Debug, Clone)] +struct InstConfig { + inst: Inst, require: Vec, reg_read: HashMap, reg_write: HashMap, - var_prefix: String, } struct SpecConverter<'ir, B: BV> { cfg: SpecConfig, iarch: &'ir Initialized<'ir, B>, +} + +impl<'ir, B: BV> SpecConverter<'ir, B> { + fn new(cfg: SpecConfig, iarch: &'ir Initialized<'ir, B>) -> Self { + Self { + cfg: cfg.clone(), + iarch, + } + } + + fn generate(&self) -> anyhow::Result { + // Derive conditions for each case. + let conds: Vec = self + .cfg + .cases + .iter() + .map(|c| self.case(c)) + .collect::>()?; + let cond = Conditions::merge(conds); + + let spec = Spec { + term: spec_ident(self.cfg.term.clone()), + args: self.cfg.args.iter().cloned().map(spec_ident).collect(), + requires: cond.requires, + provides: cond.provides, + }; + + Ok(spec) + } + + fn case(&self, case: &InstConfig) -> anyhow::Result { + // Assemble instruction. + let opcodes = opcodes(&case.inst); + assert_eq!(opcodes.len(), 1); + let opcode = opcodes[0]; + + // ISLA trace. + let paths = trace_opcode(opcode, &self.iarch)?; + + // TODO(mbm): handle multiple paths + assert_eq!(paths.len(), 1); + let events = &paths[0]; + + // Filter. + let events = tree_shake(events); - // Specification object under construction. - spec: Spec, + // Convert. + let mut converter = TraceConverter::new(case.clone(), &self.iarch); + let conds = converter.convert()?; + + Ok(conds) + } +} + +struct TraceConverter<'ir, B: BV> { + cfg: InstConfig, + iarch: &'ir Initialized<'ir, B>, // Keep track of registers read and written in the trace. reg_reads: HashSet, @@ -517,17 +603,12 @@ struct SpecConverter<'ir, B: BV> { funty: HashMap, smtlib::Ty)>, } -impl<'ir, B: BV> SpecConverter<'ir, B> { - fn new(cfg: SpecConfig, iarch: &'ir Initialized<'ir, B>) -> Self { +impl<'ir, B: BV> TraceConverter<'ir, B> { + fn new(cfg: InstConfig, iarch: &'ir Initialized<'ir, B>) -> Self { Self { cfg: cfg.clone(), iarch, - spec: Spec { - term: spec_ident(cfg.term), - args: cfg.args.iter().cloned().map(spec_ident).collect(), - requires: cfg.require, - provides: vec![], - }, + reg_reads: HashSet::new(), reg_writes: HashSet::new(), ty: HashMap::new(), @@ -535,13 +616,35 @@ impl<'ir, B: BV> SpecConverter<'ir, B> { } } - fn convert(&mut self, events: &Vec>) -> anyhow::Result { + fn convert(&mut self) -> anyhow::Result { + // Assemble instruction. + let opcodes = opcodes(&self.cfg.inst); + assert_eq!(opcodes.len(), 1); + let opcode = opcodes[0]; + + // ISLA trace. + let paths = trace_opcode(opcode, &self.iarch)?; + + // TODO(mbm): handle multiple paths + assert_eq!(paths.len(), 1); + let events = &paths[0]; + + // Filter. + let events = tree_shake(events); + + // Convert into conditions. + let mut conds = Conditions { + provides: Vec::new(), + requires: self.cfg.require.clone(), + }; + for event in events { - if let Some(exp) = self.event(event)? { - self.spec.provides.push(exp); + if let Some(exp) = self.event(&event)? { + conds.provides.push(exp); } } - Ok(self.spec.clone()) + + Ok(conds) } fn event(&mut self, event: &Event) -> anyhow::Result> { @@ -720,7 +823,7 @@ impl<'ir, B: BV> SpecConverter<'ir, B> { } fn sym(&self, s: &Sym) -> SpecExpr { - spec_var(format!("{}{}", self.cfg.var_prefix, s)) + spec_var(format!("v{}", s)) } fn infer(&self, exp: &smtlib::Exp) -> Option { @@ -833,20 +936,20 @@ fn spec_bits(bits: &[bool]) -> SpecExpr { .unwrap() } +fn spec_and(args: Vec) -> SpecExpr { + spec_op(SpecOp::And, args) +} + +fn spec_or(args: Vec) -> SpecExpr { + spec_op(SpecOp::Or, args) +} + fn spec_unary(op: SpecOp, x: SpecExpr) -> SpecExpr { - SpecExpr::Op { - op, - args: vec![x], - pos: Pos::default(), - } + spec_op(op, vec![x]) } fn spec_binary(op: SpecOp, x: SpecExpr, y: SpecExpr) -> SpecExpr { - SpecExpr::Op { - op, - args: vec![x, y], - pos: Pos::default(), - } + spec_op(op, vec![x, y]) } fn spec_eq(x: SpecExpr, y: SpecExpr) -> SpecExpr { @@ -854,9 +957,13 @@ fn spec_eq(x: SpecExpr, y: SpecExpr) -> SpecExpr { } fn spec_ternary(op: SpecOp, x: SpecExpr, y: SpecExpr, z: SpecExpr) -> SpecExpr { + spec_op(op, vec![x, y, z]) +} + +fn spec_op(op: SpecOp, args: Vec) -> SpecExpr { SpecExpr::Op { op, - args: vec![x, y, z], + args: args, pos: Pos::default(), } } From 3e137e8d0565add06425e7821105d437be1265ac Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Fri, 26 Jan 2024 00:14:45 -0500 Subject: [PATCH 52/73] generate more alu ops --- .../isle/veri/veri_engine/src/bin/isaspec.rs | 126 ++++++++++-------- 1 file changed, 70 insertions(+), 56 deletions(-) diff --git a/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs b/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs index b44f0ccc52ae..16df9b6d43dd 100644 --- a/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs +++ b/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs @@ -19,7 +19,6 @@ use isla_lib::simplify::{self, WriteOpts}; use isla_lib::smt::smtlib; use isla_lib::smt::{self, Checkpoint, Event, Solver, Sym}; use isla_lib::zencode; -use itertools::Itertools; use sha2::{Digest, Sha256}; use std::collections::{HashMap, HashSet}; use std::io::prelude::*; @@ -57,7 +56,7 @@ fn main() -> anyhow::Result<()> { let cfg = define(); // Generate spec. - let mut spec_converter = SpecConverter::new(cfg, &iarch); + let spec_converter = SpecConverter::new(cfg, &iarch); let spec = spec_converter.generate()?; printer::dump(&spec)?; @@ -81,6 +80,34 @@ fn main() -> anyhow::Result<()> { /// Define specificiations to generate. fn define() -> SpecConfig { + // ALUOp + let alu_ops = vec![ + ALUOp::Add, + ALUOp::Sub, + ALUOp::Orr, + ALUOp::OrrNot, + ALUOp::And, + // ALUOp::AndS, // 2 code paths + ALUOp::AndNot, + ALUOp::Eor, + ALUOp::EorNot, + //ALUOp::AddS, + //ALUOp::SubS, + //ALUOp::SMulH, + //ALUOp::UMulH, + //ALUOp::SDiv, + //ALUOp::UDiv, + //ALUOp::RotR, + ALUOp::Lsr, + ALUOp::Asr, + ALUOp::Lsl, + //ALUOp::Adc, + //ALUOp::AdcS, + //ALUOp::Sbc, + //ALUOp::SbcS, + ]; + + // AluRRR SpecConfig { // Spec signature. term: "MInst.AluRRR".to_string(), @@ -88,34 +115,38 @@ fn define() -> SpecConfig { .map(String::from) .to_vec(), - cases: vec![InstConfig { - inst: Inst::AluRRR { - alu_op: ALUOp::Add, - size: OperandSize::Size64, - rd: writable_xreg(4), - rn: xreg(5), - rm: xreg(6), - }, - - // Requires. - require: vec![ - spec_eq( - spec_var("alu_op".to_string()), - spec_enum("ALUOp".to_string(), "Add".to_string()), - ), - spec_eq( - spec_var("size".to_string()), - spec_enum("OperandSize".to_string(), "Size64".to_string()), - ), - ], - - // Register read/write bindings. - reg_read: HashMap::from([ - ("R5".to_string(), "rn".to_string()), - ("R6".to_string(), "rm".to_string()), - ]), - reg_write: HashMap::from([("R4".to_string(), "rd".to_string())]), - }], + cases: alu_ops + .iter() + .copied() + .map(|alu_op| InstConfig { + inst: Inst::AluRRR { + alu_op, + size: OperandSize::Size64, + rd: writable_xreg(4), + rn: xreg(5), + rm: xreg(6), + }, + + // Requires. + require: vec![ + spec_eq( + spec_var("alu_op".to_string()), + spec_enum("ALUOp".to_string(), format!("{alu_op:?}")), + ), + spec_eq( + spec_var("size".to_string()), + spec_enum("OperandSize".to_string(), "Size64".to_string()), + ), + ], + + // Register read/write bindings. + reg_read: HashMap::from([ + ("R5".to_string(), "rn".to_string()), + ("R6".to_string(), "rm".to_string()), + ]), + reg_write: HashMap::from([("R4".to_string(), "rd".to_string())]), + }) + .collect(), } } @@ -567,25 +598,8 @@ impl<'ir, B: BV> SpecConverter<'ir, B> { } fn case(&self, case: &InstConfig) -> anyhow::Result { - // Assemble instruction. - let opcodes = opcodes(&case.inst); - assert_eq!(opcodes.len(), 1); - let opcode = opcodes[0]; - - // ISLA trace. - let paths = trace_opcode(opcode, &self.iarch)?; - - // TODO(mbm): handle multiple paths - assert_eq!(paths.len(), 1); - let events = &paths[0]; - - // Filter. - let events = tree_shake(events); - - // Convert. let mut converter = TraceConverter::new(case.clone(), &self.iarch); let conds = converter.convert()?; - Ok(conds) } } @@ -774,21 +788,23 @@ impl<'ir, B: BV> TraceConverter<'ir, B> { | Bvmul(lhs, rhs) | Bvshl(lhs, rhs) | Bvlshr(lhs, rhs) - | Concat(lhs, rhs) => spec_binary(exp_spec_op(exp), self.exp(lhs), self.exp(rhs)), - // Bvudiv(Box>, Box>), // Bvsdiv(Box>, Box>), // Bvurem(Box>, Box>), - // Bvsrem(Box>, Box>), + | Bvsrem(lhs, rhs) // Bvsmod(Box>, Box>), // Bvult(Box>, Box>), - // Bvslt(Box>, Box>), + | Bvslt(lhs, rhs) // Bvule(Box>, Box>), // Bvsle(Box>, Box>), // Bvuge(Box>, Box>), // Bvsge(Box>, Box>), // Bvugt(Box>, Box>), // Bvsgt(Box>, Box>), + // Bvlshr(Box>, Box>), + | Bvashr(lhs, rhs) + | Concat(lhs, rhs) => spec_binary(exp_spec_op(exp), self.exp(lhs), self.exp(rhs)), + Extract(i, j, exp) => spec_ternary( SpecOp::Extract, spec_const_int(*i), @@ -803,8 +819,6 @@ impl<'ir, B: BV> TraceConverter<'ir, B> { _ => panic!("extension applies to bitvector types"), }, - // Bvlshr(Box>, Box>), - // Bvashr(Box>, Box>), Ite(c, t, e) => spec_ternary(SpecOp::If, self.exp(c), self.exp(t), self.exp(e)), // App(Sym, Vec>), @@ -861,10 +875,10 @@ fn exp_spec_op(exp: &smtlib::Exp) -> SpecOp { // Bvudiv(Box>, Box>), // Bvsdiv(Box>, Box>), // Bvurem(Box>, Box>), - // Bvsrem(Box>, Box>), + Bvsrem(..) => SpecOp::BVSrem, // Bvsmod(Box>, Box>), // Bvult(Box>, Box>), - // Bvslt(Box>, Box>), + Bvslt(..) => SpecOp::BVSlt, // Bvule(Box>, Box>), // Bvsle(Box>, Box>), // Bvuge(Box>, Box>), @@ -875,7 +889,7 @@ fn exp_spec_op(exp: &smtlib::Exp) -> SpecOp { SignExtend(..) => SpecOp::SignExt, Bvshl(..) => SpecOp::BVShl, Bvlshr(..) => SpecOp::BVLshr, - // Bvashr(Box>, Box>), + Bvashr(..) => SpecOp::BVAshr, Concat(..) => SpecOp::Concat, // Ite(Box>, Box>, Box>), // App(Sym, Vec>), From 46f554db8f5efcf0f57a44f097e3831312c1cdf7 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Fri, 26 Jan 2024 00:22:12 -0500 Subject: [PATCH 53/73] keep debug output --- .../isle/veri/veri_engine/src/bin/isaspec.rs | 61 +++++-------------- 1 file changed, 16 insertions(+), 45 deletions(-) diff --git a/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs b/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs index 16df9b6d43dd..b832ee5706b4 100644 --- a/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs +++ b/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs @@ -60,21 +60,6 @@ fn main() -> anyhow::Result<()> { let spec = spec_converter.generate()?; printer::dump(&spec)?; - // // Assemble. - // let opcodes = opcodes(&inst); - // assert_eq!(opcodes.len(), 1); - // let opcode = opcodes[0]; - - // // Show assembly. - // let asm = inst.print_with_state(&mut EmitState::default(), &mut AllocationConsumer::new(&[])); - - // println!("--------------------------------------------------"); - // println!("inst = {inst:?}"); - // println!("opcode = {opcode:08x}"); - // println!("asm = {asm}"); - // println!("config = {cfg:?}"); - // println!(""); - Ok(()) } @@ -150,35 +135,6 @@ fn define() -> SpecConfig { } } -// struct SpecBuilder<'ir, B: BV> { -// term: String, -// params: Vec, -// inst: Inst, -// iarch: &'ir Initialized<'ir, B>, -// } -// -// impl<'ir, B: BV> SpecBuilder<'ir, B> { -// fn build(&self) -> anyhow::Result { -// // Assemble instruction. -// let opcodes = opcodes(&self.inst); -// assert_eq!(opcodes.len(), 1); -// let opcode = opcodes[0]; -// -// // ISLA trace. -// let paths = trace_opcode(opcode, &self.iarch)?; -// -// // TODO(mbm): handle multiple paths -// assert_eq!(paths.len(), 1); -// let events = &paths[0]; -// -// // Filter. -// let events = tree_shake(events); -// -// // Generate spec. -// trace_to_spec(&events) -// } -// } - fn assemble(inst: &Inst) -> Vec { let flags = settings::Flags::new(settings::builder()); let emit_info = EmitInfo::new(flags); @@ -631,11 +587,22 @@ impl<'ir, B: BV> TraceConverter<'ir, B> { } fn convert(&mut self) -> anyhow::Result { + let inst = &self.cfg.inst; + // Assemble instruction. - let opcodes = opcodes(&self.cfg.inst); + let opcodes = opcodes(inst); assert_eq!(opcodes.len(), 1); let opcode = opcodes[0]; + // Debugging. + let asm = + inst.print_with_state(&mut EmitState::default(), &mut AllocationConsumer::new(&[])); + + println!("inst = {inst:#?}"); + println!("opcode = {opcode:08x}"); + println!("asm = {asm}"); + println!("----"); + // ISLA trace. let paths = trace_opcode(opcode, &self.iarch)?; @@ -643,6 +610,10 @@ impl<'ir, B: BV> TraceConverter<'ir, B> { assert_eq!(paths.len(), 1); let events = &paths[0]; + // Debugging. + write_events(events, self.iarch)?; + println!("--------------------------------------------------"); + // Filter. let events = tree_shake(events); From f7decdd6495cf101d7b42a73afeb7de1350c8347 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Fri, 26 Jan 2024 00:31:00 -0500 Subject: [PATCH 54/73] elide no-op zext --- cranelift/isle/veri/veri_engine/src/bin/isaspec.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs b/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs index b832ee5706b4..ec26d003f1d5 100644 --- a/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs +++ b/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs @@ -776,6 +776,7 @@ impl<'ir, B: BV> TraceConverter<'ir, B> { | Bvashr(lhs, rhs) | Concat(lhs, rhs) => spec_binary(exp_spec_op(exp), self.exp(lhs), self.exp(rhs)), + // TODO: elide no-op extract ops for example (extract 63 0 x) for a 64-bit x Extract(i, j, exp) => spec_ternary( SpecOp::Extract, spec_const_int(*i), @@ -783,12 +784,13 @@ impl<'ir, B: BV> TraceConverter<'ir, B> { self.exp(exp), ), + ZeroExtend(0, x) | SignExtend(0, x) => self.exp(x), ZeroExtend(n, x) | SignExtend(n, x) => match self.infer(x).unwrap() { smtlib::Ty::BitVec(w) => { spec_binary(exp_spec_op(exp), spec_const_int(n + w), self.exp(x)) } _ => panic!("extension applies to bitvector types"), - }, + } Ite(c, t, e) => spec_ternary(SpecOp::If, self.exp(c), self.exp(t), self.exp(e)), From 79d673cc0ab737e00295e2abdc28d13c06ad78bb Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Fri, 26 Jan 2024 14:09:57 -0500 Subject: [PATCH 55/73] veriisle: isaspec option to write to file --- cranelift/isle/veri/veri_engine/src/bin/isaspec.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs b/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs index ec26d003f1d5..4664d2d232ba 100644 --- a/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs +++ b/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs @@ -29,7 +29,8 @@ use std::sync::Arc; fn main() -> anyhow::Result<()> { // Command-line options. let mut opts = opts::common_opts(); - opts.optflag("", "filter", "filter relevant events from the trace"); + opts.optopt("", "spec", "path to output spec", ""); + opts.optopt("", "width", "line length for output spec", ""); // Build ISLA architecture. let mut hasher = Sha256::new(); @@ -58,7 +59,16 @@ fn main() -> anyhow::Result<()> { // Generate spec. let spec_converter = SpecConverter::new(cfg, &iarch); let spec = spec_converter.generate()?; - printer::dump(&spec)?; + + // Output. + let width = matches.opt_get_default("width", 78)?; + if let Some(path) = matches.opt_str("spec") { + let mut file = std::fs::File::create(path)?; + printer::print(&spec, width, &mut file)?; + } else { + let mut stdout = std::io::stdout(); + printer::print(&spec, width, &mut stdout)?; + }; Ok(()) } From b9da528740ef6ec85c22fa07353ed6a6ec111e20 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Fri, 26 Jan 2024 14:15:54 -0500 Subject: [PATCH 56/73] isle: parse spec implication operator --- cranelift/isle/isle/src/parser.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/cranelift/isle/isle/src/parser.rs b/cranelift/isle/isle/src/parser.rs index 174b02439880..cc8d73f901d8 100644 --- a/cranelift/isle/isle/src/parser.rs +++ b/cranelift/isle/isle/src/parser.rs @@ -475,6 +475,7 @@ impl<'a> Parser<'a> { "and" => Ok(SpecOp::And), "not" => Ok(SpecOp::Not), "or" => Ok(SpecOp::Or), + "=>" => Ok(SpecOp::Imp), "<=" => Ok(SpecOp::Lte), "<" => Ok(SpecOp::Lt), ">=" => Ok(SpecOp::Gte), From 5281b497730167cee0d5f9c29fb03526f159dcd8 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Fri, 26 Jan 2024 14:16:37 -0500 Subject: [PATCH 57/73] codegen: add inst_specs.isle to aarch64 isle compilation --- cranelift/codegen/build.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cranelift/codegen/build.rs b/cranelift/codegen/build.rs index 3ebb1c18c96e..21f10fd9abf0 100644 --- a/cranelift/codegen/build.rs +++ b/cranelift/codegen/build.rs @@ -187,7 +187,8 @@ fn get_isle_compilations( make_isle_source_path_relative(&cur_dir, crate_dir.join("src").join("prelude_opt.isle")); let prelude_lower_isle = make_isle_source_path_relative(&cur_dir, crate_dir.join("src").join("prelude_lower.isle")); - let inst_specs = make_isle_source_path_relative(&cur_dir, crate_dir.join("src").join("inst_specs.isle")); + let inst_specs = + make_isle_source_path_relative(&cur_dir, crate_dir.join("src").join("inst_specs.isle")); // Directory for mid-end optimizations. let src_opts = make_isle_source_path_relative(&cur_dir, crate_dir.join("src").join("opts")); @@ -253,6 +254,7 @@ fn get_isle_compilations( prelude_lower_isle.clone(), src_isa_aarch64.join("inst.isle"), src_isa_aarch64.join("inst_neon.isle"), + src_isa_aarch64.join("inst_specs.isle"), inst_specs.clone(), src_isa_aarch64.join("lower.isle"), src_isa_aarch64.join("lower_dynamic_neon.isle"), From 176292f9d8575d73e8a1039bd3a76dd3702ec7d0 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Mon, 29 Jan 2024 19:01:46 -0500 Subject: [PATCH 58/73] veriisle: generate instruction specs --- cranelift/codegen/src/isa/aarch64/inst.isle | 5 +- .../codegen/src/isa/aarch64/inst_specs.isle | 82 +++++++++++++++++++ cranelift/codegen/src/prelude_lower.isle | 4 + .../isle/veri/veri_engine/src/bin/isaspec.rs | 53 +++++++----- cranelift/isle/veri/veri_engine/src/solver.rs | 4 + .../veri/veri_engine/src/type_inference.rs | 20 ++++- .../isle/veri/veri_engine/tests/utils/mod.rs | 5 ++ cranelift/isle/veri/veri_engine/tests/veri.rs | 11 +++ 8 files changed, 162 insertions(+), 22 deletions(-) create mode 100644 cranelift/codegen/src/isa/aarch64/inst_specs.isle diff --git a/cranelift/codegen/src/isa/aarch64/inst.isle b/cranelift/codegen/src/isa/aarch64/inst.isle index fb497367f79b..a2d3a53992bf 100644 --- a/cranelift/codegen/src/isa/aarch64/inst.isle +++ b/cranelift/codegen/src/isa/aarch64/inst.isle @@ -2034,7 +2034,10 @@ (or (= op (ALUOp.Lsr)) (= op (ALUOp.Asr)) (= op (ALUOp.Lsl))) (or (= t 8) (= t 16) (= t 32) (= t 64)))) (decl alu_rrr (ALUOp Type Reg Reg) Reg) -(rule (alu_rrr op ty src1 src2) +(instantiate alu_rrr + ((args (bv 8) Int (bv 64) (bv 64)) (ret (bv 64)) (canon (bv 64))) +) +(rule alu_rrr_emit (alu_rrr op ty src1 src2) (let ((dst WritableReg (temp_writable_reg $I64)) (_ Unit (emit (MInst.AluRRR op (operand_size ty) dst src1 src2)))) dst)) diff --git a/cranelift/codegen/src/isa/aarch64/inst_specs.isle b/cranelift/codegen/src/isa/aarch64/inst_specs.isle new file mode 100644 index 000000000000..9956d8e9d7e1 --- /dev/null +++ b/cranelift/codegen/src/isa/aarch64/inst_specs.isle @@ -0,0 +1,82 @@ +(spec + (MInst.AluRRR alu_op size rd rn rm) + (provide + (=> + (and (= alu_op (ALUOp.Add)) (= size (OperandSize.Size64))) + (and + (= rn v536) + (= rm v538) + (= + v581 + (bvadd + (extract 63 0 (zero_ext 128 (extract 63 0 v536))) + (extract 63 0 (zero_ext 128 (extract 63 0 v538))))) + (= rd v581))) + (=> + (and (= alu_op (ALUOp.Sub)) (= size (OperandSize.Size64))) + (and + (= rn v536) + (= rm v538) + (= + v584 + (bvadd + (extract + 63 + 0 + (bvadd + (zero_ext 128 (extract 63 0 v536)) + (zero_ext 128 (bvnot (extract 63 0 v538))))) + #x0000000000000001)) + (= rd v584))) + (=> + (and (= alu_op (ALUOp.Orr)) (= size (OperandSize.Size64))) + (and + (= rn v544) + (= rm v546) + (= v550 (bvor (extract 63 0 v544) (extract 63 0 v546))) + (= rd v550))) + (=> + (and (= alu_op (ALUOp.OrrNot)) (= size (OperandSize.Size64))) + (and + (= rn v544) + (= rm v546) + (= v551 (bvor (extract 63 0 v544) (bvnot (extract 63 0 v546)))) + (= rd v551))) + (=> + (and (= alu_op (ALUOp.And)) (= size (OperandSize.Size64))) + (and + (= rn v544) + (= rm v546) + (= v550 (bvand (extract 63 0 v544) (extract 63 0 v546))) + (= rd v550))) + (=> + (and (= alu_op (ALUOp.AndNot)) (= size (OperandSize.Size64))) + (and + (= rn v544) + (= rm v546) + (= v551 (bvand (extract 63 0 v544) (bvnot (extract 63 0 v546)))) + (= rd v551))) + (=> + (and (= alu_op (ALUOp.Eor)) (= size (OperandSize.Size64))) + (and + (= rn v544) + (= rm v546) + (= v550 (bvxor (extract 63 0 v544) (extract 63 0 v546))) + (= rd v550))) + (=> + (and (= alu_op (ALUOp.EorNot)) (= size (OperandSize.Size64))) + (and + (= rn v544) + (= rm v546) + (= v551 (bvxor (extract 63 0 v544) (bvnot (extract 63 0 v546)))) + (= rd v551)))) + (require + (or + (and (= alu_op (ALUOp.Add)) (= size (OperandSize.Size64))) + (and (= alu_op (ALUOp.Sub)) (= size (OperandSize.Size64))) + (and (= alu_op (ALUOp.Orr)) (= size (OperandSize.Size64))) + (and (= alu_op (ALUOp.OrrNot)) (= size (OperandSize.Size64))) + (and (= alu_op (ALUOp.And)) (= size (OperandSize.Size64))) + (and (= alu_op (ALUOp.AndNot)) (= size (OperandSize.Size64))) + (and (= alu_op (ALUOp.Eor)) (= size (OperandSize.Size64))) + (and (= alu_op (ALUOp.EorNot)) (= size (OperandSize.Size64)))))) diff --git a/cranelift/codegen/src/prelude_lower.isle b/cranelift/codegen/src/prelude_lower.isle index f6eb20e419b5..7bb52cd6908f 100644 --- a/cranelift/codegen/src/prelude_lower.isle +++ b/cranelift/codegen/src/prelude_lower.isle @@ -107,6 +107,7 @@ ;; Get a temporary register for writing. (decl temp_writable_reg (Type) WritableReg) (extern constructor temp_writable_reg temp_writable_reg) +(spec (temp_writable_reg ty) (provide (= ty (widthof result)))) ;; Get a temporary register for reading. (decl temp_reg (Type) Reg) @@ -266,6 +267,7 @@ ;; Turn a `Writable` into a `Reg` via `Writable::to_reg`. (decl pure writable_reg_to_reg (WritableReg) Reg) (extern constructor writable_reg_to_reg writable_reg_to_reg) +(spec (writable_reg_to_reg reg) (provide (= result reg))) ;; Extract the result values for the given instruction. (decl inst_results (ValueSlice) Inst) @@ -332,6 +334,8 @@ (decl emit (MInst) Unit) (extern constructor emit emit) +; TODO(mbm): what is the right spec for emit? +(spec (emit inst) (provide true)) ;; Sink an instruction. ;; diff --git a/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs b/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs index 4664d2d232ba..e65f4ec048f7 100644 --- a/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs +++ b/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs @@ -3,7 +3,7 @@ use cranelift_codegen::settings; use cranelift_codegen::AllocationConsumer; use cranelift_codegen::MachBuffer; use cranelift_codegen::MachInstEmit; -use cranelift_isle::ast::{Ident, Spec, SpecExpr, SpecOp}; +use cranelift_isle::ast::{Def, Defs, Ident, Spec, SpecExpr, SpecOp}; use cranelift_isle::lexer::Pos; use cranelift_isle::printer; use crossbeam::queue::SegQueue; @@ -54,10 +54,10 @@ fn main() -> anyhow::Result<()> { ); // Spec configuration. - let cfg = define(); + let cfgs = define(); - // Generate spec. - let spec_converter = SpecConverter::new(cfg, &iarch); + // Generate specs. + let spec_converter = SpecConverter::new(cfgs, &iarch); let spec = spec_converter.generate()?; // Output. @@ -74,7 +74,7 @@ fn main() -> anyhow::Result<()> { } /// Define specificiations to generate. -fn define() -> SpecConfig { +fn define() -> Vec { // ALUOp let alu_ops = vec![ ALUOp::Add, @@ -82,10 +82,13 @@ fn define() -> SpecConfig { ALUOp::Orr, ALUOp::OrrNot, ALUOp::And, - // ALUOp::AndS, // 2 code paths ALUOp::AndNot, ALUOp::Eor, ALUOp::EorNot, + //ALUOp::Lsr, + //ALUOp::Asr, + //ALUOp::Lsl, + //ALUOp::AndS, // 2 code paths //ALUOp::AddS, //ALUOp::SubS, //ALUOp::SMulH, @@ -93,9 +96,6 @@ fn define() -> SpecConfig { //ALUOp::SDiv, //ALUOp::UDiv, //ALUOp::RotR, - ALUOp::Lsr, - ALUOp::Asr, - ALUOp::Lsl, //ALUOp::Adc, //ALUOp::AdcS, //ALUOp::Sbc, @@ -103,7 +103,7 @@ fn define() -> SpecConfig { ]; // AluRRR - SpecConfig { + let alu_rrr = SpecConfig { // Spec signature. term: "MInst.AluRRR".to_string(), args: ["alu_op", "size", "rd", "rn", "rm"] @@ -142,7 +142,9 @@ fn define() -> SpecConfig { reg_write: HashMap::from([("R4".to_string(), "rd".to_string())]), }) .collect(), - } + }; + + vec![alu_rrr] } fn assemble(inst: &Inst) -> Vec { @@ -531,22 +533,35 @@ struct InstConfig { } struct SpecConverter<'ir, B: BV> { - cfg: SpecConfig, + cfgs: Vec, iarch: &'ir Initialized<'ir, B>, } impl<'ir, B: BV> SpecConverter<'ir, B> { - fn new(cfg: SpecConfig, iarch: &'ir Initialized<'ir, B>) -> Self { + fn new(cfgs: Vec, iarch: &'ir Initialized<'ir, B>) -> Self { Self { - cfg: cfg.clone(), + cfgs: cfgs.clone(), iarch, } } - fn generate(&self) -> anyhow::Result { + fn generate(&self) -> anyhow::Result { + let defs: Vec = self + .cfgs + .iter() + .map(|cfg| Ok(Def::Spec(self.spec(cfg)?))) + .collect::>()?; + + Ok(Defs { + defs, + filenames: vec![], + file_texts: vec![], + }) + } + + fn spec(&self, cfg: &SpecConfig) -> anyhow::Result { // Derive conditions for each case. - let conds: Vec = self - .cfg + let conds: Vec = cfg .cases .iter() .map(|c| self.case(c)) @@ -554,8 +569,8 @@ impl<'ir, B: BV> SpecConverter<'ir, B> { let cond = Conditions::merge(conds); let spec = Spec { - term: spec_ident(self.cfg.term.clone()), - args: self.cfg.args.iter().cloned().map(spec_ident).collect(), + term: spec_ident(cfg.term.clone()), + args: cfg.args.iter().cloned().map(spec_ident).collect(), requires: cond.requires, provides: cond.provides, }; diff --git a/cranelift/isle/veri/veri_engine/src/solver.rs b/cranelift/isle/veri/veri_engine/src/solver.rs index 84fda93315f9..2baf12cc1d11 100644 --- a/cranelift/isle/veri/veri_engine/src/solver.rs +++ b/cranelift/isle/veri/veri_engine/src/solver.rs @@ -457,6 +457,10 @@ impl SolverCtx { narrow_decl: SExpr, name: Option, ) -> SExpr { + println!( + "widen: tyvar={tyvar:?} narrow_width={narrow_width:?} name={name:?} bitwidth={}", + self.bitwidth + ); let width = self.bitwidth.checked_sub(narrow_width).unwrap(); if width > 0 { let mut narrow_name = format!("narrow__{}", tyvar); diff --git a/cranelift/isle/veri/veri_engine/src/type_inference.rs b/cranelift/isle/veri/veri_engine/src/type_inference.rs index 8520e0c1720b..92dcd947fb89 100644 --- a/cranelift/isle/veri/veri_engine/src/type_inference.rs +++ b/cranelift/isle/veri/veri_engine/src/type_inference.rs @@ -453,6 +453,24 @@ fn add_annotation_constraints( t, ) } + annotation_ir::Expr::Imp(x, y) => { + let (e1, t1) = add_annotation_constraints(*x, tree, annotation_info); + let (e2, t2) = add_annotation_constraints(*y, tree, annotation_info); + let t = tree.next_type_var; + + tree.concrete_constraints + .insert(TypeExpr::Concrete(t1, annotation_ir::Type::Bool)); + tree.concrete_constraints + .insert(TypeExpr::Concrete(t2, annotation_ir::Type::Bool)); + tree.concrete_constraints + .insert(TypeExpr::Concrete(t, annotation_ir::Type::Bool)); + + tree.next_type_var += 1; + ( + veri_ir::Expr::Binary(veri_ir::BinaryOp::Imp, Box::new(e1), Box::new(e2)), + t, + ) + } annotation_ir::Expr::Lte(x, y) => { let (e1, t1) = add_annotation_constraints(*x, tree, annotation_info); let (e2, t2) = add_annotation_constraints(*y, tree, annotation_info); @@ -1365,8 +1383,6 @@ fn add_annotation_constraints( tree.next_type_var += 1; (veri_ir::Expr::BVPopcnt(Box::new(e1)), t) } - - _ => todo!("expr {:#?} not yet implemented", expr), }; tree.ty_vars.insert(e.clone(), t); (e, t) diff --git a/cranelift/isle/veri/veri_engine/tests/utils/mod.rs b/cranelift/isle/veri/veri_engine/tests/utils/mod.rs index ed87cfe81359..13f6d772a06c 100644 --- a/cranelift/isle/veri/veri_engine/tests/utils/mod.rs +++ b/cranelift/isle/veri/veri_engine/tests/utils/mod.rs @@ -231,6 +231,11 @@ pub fn test_aarch64_rule_with_lhs_termname(rulename: &str, termname: &str, tr: T .join("../../../codegen/src/isa/aarch64") .join("inst.isle"), ); + inputs.push( + cur_dir + .join("../../../codegen/src/isa/aarch64") + .join("inst_specs.isle"), + ); inputs.push( cur_dir .join("../../../codegen/src/isa/aarch64") diff --git a/cranelift/isle/veri/veri_engine/tests/veri.rs b/cranelift/isle/veri/veri_engine/tests/veri.rs index 2d5d00c68209..15b6d7a98eb9 100644 --- a/cranelift/isle/veri/veri_engine/tests/veri.rs +++ b/cranelift/isle/veri/veri_engine/tests/veri.rs @@ -3200,6 +3200,17 @@ fn test_broken_imm_udiv_cve_underlying_32() { }) } +#[test] +fn test_named_alu_rrr_emit() { + run_and_retry(|| { + test_aarch64_rule_with_lhs_termname_simple( + "alu_rrr_emit", + "alu_rrr", + vec![(Bitwidth::I64, VerificationResult::Success)], + ) + }) +} + // x64 #[test] From b5f2b683b6434376db3d3b8b290ec93643f0f1cb Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Wed, 31 Jan 2024 12:46:34 -0500 Subject: [PATCH 59/73] verify add lowering to alu_rrr --- cranelift/codegen/src/isa/aarch64/inst.isle | 60 ++++++++++++------- .../isle/veri/veri_engine/src/bin/isaspec.rs | 8 +++ cranelift/isle/veri/veri_engine/tests/veri.rs | 15 +++++ 3 files changed, 61 insertions(+), 22 deletions(-) diff --git a/cranelift/codegen/src/isa/aarch64/inst.isle b/cranelift/codegen/src/isa/aarch64/inst.isle index a2d3a53992bf..30a9482f621d 100644 --- a/cranelift/codegen/src/isa/aarch64/inst.isle +++ b/cranelift/codegen/src/isa/aarch64/inst.isle @@ -2015,24 +2015,31 @@ dst)) ;; Helper for emitting `MInst.AluRRR` instructions. -(spec (alu_rrr op t a b) +(spec (alu_rrr op ty a b) (provide - (= result (switch op - ((ALUOp.Lsr) - (if (<= t 32) - (conv_to 64 (bvlshr (extract 31 0 a) (bvand (bvsub (int2bv 32 32) #x00000001) (extract 31 0 b)))) - (bvlshr a (bvand (bvsub (int2bv 64 64) #x0000000000000001) b)))) - ((ALUOp.Asr) - (if (<= t 32) - (conv_to 64 (bvashr (extract 31 0 a) (bvand (bvsub (int2bv 32 32) #x00000001) (extract 31 0 b)))) - (bvashr a (bvand (bvsub (int2bv 64 64) #x0000000000000001) b)))) - ((ALUOp.Lsl) - (if (<= t 32) - (conv_to 64 (bvshl (extract 31 0 a) (bvand (bvsub (int2bv 32 32) #x00000001) (extract 31 0 b)))) - (bvshl a (bvand (bvsub (int2bv 64 64) #x0000000000000001) b))))))) + (= result (switch op + ;; ((ALUOp.Lsr) + ;; (if (<= t 32) + ;; (conv_to 64 (bvlshr (extract 31 0 a) (bvand (bvsub (int2bv 32 32) #x00000001) (extract 31 0 b)))) + ;; (bvlshr a (bvand (bvsub (int2bv 64 64) #x0000000000000001) b)))) + ;; ((ALUOp.Asr) + ;; (if (<= t 32) + ;; (conv_to 64 (bvashr (extract 31 0 a) (bvand (bvsub (int2bv 32 32) #x00000001) (extract 31 0 b)))) + ;; (bvashr a (bvand (bvsub (int2bv 64 64) #x0000000000000001) b)))) + ;; ((ALUOp.Lsl) + ;; (if (<= t 32) + ;; (conv_to 64 (bvshl (extract 31 0 a) (bvand (bvsub (int2bv 32 32) #x00000001) (extract 31 0 b)))) + ;; (bvshl a (bvand (bvsub (int2bv 64 64) #x0000000000000001) b)))) + ((ALUOp.Add) + (if (<= ty 32) + (conv_to 64 (bvadd (extract 31 0 a) (extract 31 0 b))) + (bvadd a b)))))) (require - (or (= op (ALUOp.Lsr)) (= op (ALUOp.Asr)) (= op (ALUOp.Lsl))) - (or (= t 8) (= t 16) (= t 32) (= t 64)))) + ; (or (= op (ALUOp.Lsr)) (= op (ALUOp.Asr)) (= op (ALUOp.Lsl))) + (or (= op (ALUOp.Add))) + (or (= ty 8) (= ty 16) (= ty 32) (= ty 64)) + ) +) (decl alu_rrr (ALUOp Type Reg Reg) Reg) (instantiate alu_rrr ((args (bv 8) Int (bv 64) (bv 64)) (ret (bv 64)) (canon (bv 64))) @@ -2633,13 +2640,22 @@ ;; Helpers for generating `add` instructions. (spec (add ty a b) - (provide - (= result - (if (<= ty 32) - (conv_to 64 (bvadd (extract 31 0 a) (extract 31 0 b))) - (bvadd a b))))) + (provide + (= result + (if (<= ty 32) + (conv_to 64 (bvadd (extract 31 0 a) (extract 31 0 b))) + (bvadd a b))) + ) + (require + (= ty (widthof a)) + (= ty (widthof b)) + ) +) (decl add (Type Reg Reg) Reg) -(rule (add ty x y) (alu_rrr (ALUOp.Add) ty x y)) +(instantiate add + ((args Int (bv 64) (bv 64)) (ret (bv 64)) (canon (bv 64))) +) +(rule add_alu_rrr (add ty x y) (alu_rrr (ALUOp.Add) ty x y)) (spec (add_imm ty a b) (provide diff --git a/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs b/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs index e65f4ec048f7..c0bfdecdd25b 100644 --- a/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs +++ b/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs @@ -144,6 +144,14 @@ fn define() -> Vec { .collect(), }; + // Inst::Extend { + // rd: writable_xreg(1), + // rn: xreg(2), + // signed: true, + // from_bits: 8, + // to_bits: 32, + // }, + vec![alu_rrr] } diff --git a/cranelift/isle/veri/veri_engine/tests/veri.rs b/cranelift/isle/veri/veri_engine/tests/veri.rs index 15b6d7a98eb9..65ce2c75cc52 100644 --- a/cranelift/isle/veri/veri_engine/tests/veri.rs +++ b/cranelift/isle/veri/veri_engine/tests/veri.rs @@ -3200,6 +3200,21 @@ fn test_broken_imm_udiv_cve_underlying_32() { }) } +// ISA spec test: +// 1. add_alu_rrr lowers add to alu_rrr +// 2. alu_rrr lowers to MInst.AluRRR + +#[test] +fn test_named_add_alu_rrr() { + run_and_retry(|| { + test_aarch64_rule_with_lhs_termname_simple( + "add_alu_rrr", + "add", + vec![(Bitwidth::I64, VerificationResult::Success)], + ) + }) +} + #[test] fn test_named_alu_rrr_emit() { run_and_retry(|| { From 2fe39d39d251cc4e9fa9921c30cee4ac28e0356c Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Wed, 31 Jan 2024 14:31:22 -0500 Subject: [PATCH 60/73] wip --- cranelift/codegen/src/isa/aarch64/inst.isle | 21 +++-- .../codegen/src/isa/aarch64/inst_specs.isle | 84 ++----------------- .../isle/veri/veri_engine/src/bin/isaspec.rs | 14 ++-- cranelift/isle/veri/veri_engine/tests/veri.rs | 8 +- 4 files changed, 30 insertions(+), 97 deletions(-) diff --git a/cranelift/codegen/src/isa/aarch64/inst.isle b/cranelift/codegen/src/isa/aarch64/inst.isle index 30a9482f621d..5ef438c0007e 100644 --- a/cranelift/codegen/src/isa/aarch64/inst.isle +++ b/cranelift/codegen/src/isa/aarch64/inst.isle @@ -2030,14 +2030,15 @@ ;; (if (<= t 32) ;; (conv_to 64 (bvshl (extract 31 0 a) (bvand (bvsub (int2bv 32 32) #x00000001) (extract 31 0 b)))) ;; (bvshl a (bvand (bvsub (int2bv 64 64) #x0000000000000001) b)))) - ((ALUOp.Add) + ((ALUOp.And) (if (<= ty 32) - (conv_to 64 (bvadd (extract 31 0 a) (extract 31 0 b))) - (bvadd a b)))))) + (conv_to 64 (bvand (extract 31 0 a) (extract 31 0 b))) + (bvand a b)))))) (require ; (or (= op (ALUOp.Lsr)) (= op (ALUOp.Asr)) (= op (ALUOp.Lsl))) - (or (= op (ALUOp.Add))) - (or (= ty 8) (= ty 16) (= ty 32) (= ty 64)) + (or (= op (ALUOp.And))) + ; (or (= ty 8) (= ty 16) (= ty 32) (= ty 64)) + (or (= ty 64)) ) ) (decl alu_rrr (ALUOp Type Reg Reg) Reg) @@ -3169,9 +3170,15 @@ (if (<= ty 32) (conv_to 64 (bvand (extract 31 0 a) (extract 31 0 b))) (bvand a b)))) - (require (or (= ty 8) (= ty 16) (= ty 32) (= ty 64)))) + (require + ; (or (= ty 8) (= ty 16) (= ty 32) (= ty 64)) + (= ty 64) + )) (decl and_reg (Type Reg Reg) Reg) -(rule (and_reg ty x y) (alu_rrr (ALUOp.And) ty x y)) +(instantiate and_reg + ((args Int (bv 64) (bv 64)) (ret (bv 64)) (canon (bv 64))) +) +(rule and_reg_alu_rrr (and_reg ty x y) (alu_rrr (ALUOp.And) ty x y)) (spec (and_imm ty x y) (provide diff --git a/cranelift/codegen/src/isa/aarch64/inst_specs.isle b/cranelift/codegen/src/isa/aarch64/inst_specs.isle index 9956d8e9d7e1..ab4756c9d905 100644 --- a/cranelift/codegen/src/isa/aarch64/inst_specs.isle +++ b/cranelift/codegen/src/isa/aarch64/inst_specs.isle @@ -1,82 +1,8 @@ (spec (MInst.AluRRR alu_op size rd rn rm) (provide - (=> - (and (= alu_op (ALUOp.Add)) (= size (OperandSize.Size64))) - (and - (= rn v536) - (= rm v538) - (= - v581 - (bvadd - (extract 63 0 (zero_ext 128 (extract 63 0 v536))) - (extract 63 0 (zero_ext 128 (extract 63 0 v538))))) - (= rd v581))) - (=> - (and (= alu_op (ALUOp.Sub)) (= size (OperandSize.Size64))) - (and - (= rn v536) - (= rm v538) - (= - v584 - (bvadd - (extract - 63 - 0 - (bvadd - (zero_ext 128 (extract 63 0 v536)) - (zero_ext 128 (bvnot (extract 63 0 v538))))) - #x0000000000000001)) - (= rd v584))) - (=> - (and (= alu_op (ALUOp.Orr)) (= size (OperandSize.Size64))) - (and - (= rn v544) - (= rm v546) - (= v550 (bvor (extract 63 0 v544) (extract 63 0 v546))) - (= rd v550))) - (=> - (and (= alu_op (ALUOp.OrrNot)) (= size (OperandSize.Size64))) - (and - (= rn v544) - (= rm v546) - (= v551 (bvor (extract 63 0 v544) (bvnot (extract 63 0 v546)))) - (= rd v551))) - (=> - (and (= alu_op (ALUOp.And)) (= size (OperandSize.Size64))) - (and - (= rn v544) - (= rm v546) - (= v550 (bvand (extract 63 0 v544) (extract 63 0 v546))) - (= rd v550))) - (=> - (and (= alu_op (ALUOp.AndNot)) (= size (OperandSize.Size64))) - (and - (= rn v544) - (= rm v546) - (= v551 (bvand (extract 63 0 v544) (bvnot (extract 63 0 v546)))) - (= rd v551))) - (=> - (and (= alu_op (ALUOp.Eor)) (= size (OperandSize.Size64))) - (and - (= rn v544) - (= rm v546) - (= v550 (bvxor (extract 63 0 v544) (extract 63 0 v546))) - (= rd v550))) - (=> - (and (= alu_op (ALUOp.EorNot)) (= size (OperandSize.Size64))) - (and - (= rn v544) - (= rm v546) - (= v551 (bvxor (extract 63 0 v544) (bvnot (extract 63 0 v546)))) - (= rd v551)))) - (require - (or - (and (= alu_op (ALUOp.Add)) (= size (OperandSize.Size64))) - (and (= alu_op (ALUOp.Sub)) (= size (OperandSize.Size64))) - (and (= alu_op (ALUOp.Orr)) (= size (OperandSize.Size64))) - (and (= alu_op (ALUOp.OrrNot)) (= size (OperandSize.Size64))) - (and (= alu_op (ALUOp.And)) (= size (OperandSize.Size64))) - (and (= alu_op (ALUOp.AndNot)) (= size (OperandSize.Size64))) - (and (= alu_op (ALUOp.Eor)) (= size (OperandSize.Size64))) - (and (= alu_op (ALUOp.EorNot)) (= size (OperandSize.Size64)))))) + (= rn v544) + (= rm v546) + (= v550 (bvand (extract 63 0 v544) (extract 63 0 v546))) + (= rd v550)) + (require (= alu_op (ALUOp.And)) (= size (OperandSize.Size64)))) diff --git a/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs b/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs index c0bfdecdd25b..1241b0c125ca 100644 --- a/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs +++ b/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs @@ -77,14 +77,14 @@ fn main() -> anyhow::Result<()> { fn define() -> Vec { // ALUOp let alu_ops = vec![ - ALUOp::Add, - ALUOp::Sub, - ALUOp::Orr, - ALUOp::OrrNot, + //ALUOp::Add, // 128-bit ops + //ALUOp::Sub, // 128-bit ops + //ALUOp::Orr, + //ALUOp::OrrNot, ALUOp::And, - ALUOp::AndNot, - ALUOp::Eor, - ALUOp::EorNot, + //ALUOp::AndNot, + //ALUOp::Eor, + //ALUOp::EorNot, //ALUOp::Lsr, //ALUOp::Asr, //ALUOp::Lsl, diff --git a/cranelift/isle/veri/veri_engine/tests/veri.rs b/cranelift/isle/veri/veri_engine/tests/veri.rs index 65ce2c75cc52..deb83d7a8690 100644 --- a/cranelift/isle/veri/veri_engine/tests/veri.rs +++ b/cranelift/isle/veri/veri_engine/tests/veri.rs @@ -3201,15 +3201,15 @@ fn test_broken_imm_udiv_cve_underlying_32() { } // ISA spec test: -// 1. add_alu_rrr lowers add to alu_rrr +// 1. and_alu_rrr lowers and to alu_rrr // 2. alu_rrr lowers to MInst.AluRRR #[test] -fn test_named_add_alu_rrr() { +fn test_named_and_reg_alu_rrr() { run_and_retry(|| { test_aarch64_rule_with_lhs_termname_simple( - "add_alu_rrr", - "add", + "and_reg_alu_rrr", + "and_reg", vec![(Bitwidth::I64, VerificationResult::Success)], ) }) From a49bfdf1e2f9717357bff6ac167f4d221d39df46 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Wed, 31 Jan 2024 17:41:42 -0500 Subject: [PATCH 61/73] x64 footprint --- .../veri/veri_engine/src/bin/x64footprint.rs | 545 ++++++++++++++++++ 1 file changed, 545 insertions(+) create mode 100644 cranelift/isle/veri/veri_engine/src/bin/x64footprint.rs diff --git a/cranelift/isle/veri/veri_engine/src/bin/x64footprint.rs b/cranelift/isle/veri/veri_engine/src/bin/x64footprint.rs new file mode 100644 index 000000000000..17d58b8c9416 --- /dev/null +++ b/cranelift/isle/veri/veri_engine/src/bin/x64footprint.rs @@ -0,0 +1,545 @@ +use clap::Parser; +use crossbeam::queue::SegQueue; +use isla_lib::init::{initialize_architecture, Initialized}; +use isla_lib::ir::{AssertionMode, Def, IRTypeInfo, Name, Symtab, Ty, Val}; +use isla_lib::ir_lexer::new_ir_lexer; +use isla_lib::ir_parser; +use isla_lib::log; +use isla_lib::memory::{Memory, SmtKind}; +use isla_lib::simplify::{self, WriteOpts}; +use isla_lib::smt::smtlib::{self, bits64}; +use isla_lib::smt::{self, Checkpoint, Event, ReadOpts, Solver, Sym}; +use isla_lib::source_loc::SourceLoc; +use isla_lib::{ + bitvector::{b64::B64, BV}, + zencode, +}; +use isla_lib::{config::ISAConfig, executor::unfreeze_frame}; +use isla_lib::{ + error::{ExecError, IslaError}, + memory::Address, +}; +use isla_lib::{ + executor::{self, freeze_frame, LocalFrame, TaskState}, + ir::linearize, +}; +use sha2::{Digest, Sha256}; +use std::io::prelude::*; +use std::io::BufWriter; +use std::path::PathBuf; +use std::sync::Arc; + +#[derive(Parser)] +struct Options { + /// Architecture definition. + #[clap(long)] + arch: PathBuf, + + /// ISA config file. + #[clap(long)] + isa_config: PathBuf, + + /// Trace output directory. + #[clap(long, default_value = ".")] + output_dir: PathBuf, +} + +fn main() -> anyhow::Result<()> { + let options = Options::parse(); + log::set_flags(log::VERBOSE); + + // Parse ISLA Architecture. + let contents = std::fs::read_to_string(&options.arch)?; + let mut symtab = Symtab::new(); + let mut arch = parse_ir::(&contents, &mut symtab)?; + + // ISLA ISA Config. + let mut hasher = Sha256::new(); + let type_info = IRTypeInfo::new(&arch); + let isa_config = match ISAConfig::::from_file( + &mut hasher, + &options.isa_config, + None, + &symtab, + &type_info, + ) { + Ok(isa_config) => isa_config, + Err(msg) => anyhow::bail!(msg), + }; + + let linearize_functions = vec![ + // See: https://github.com/rems-project/isla-testgen/blob/a9759247bfdff9c9c39d95a4cfd85318e5bf50fe/c86-command + //"fdiv_int", + "bool_to_bits", + "bits_to_bool", + //"bit_to_bool", + //"isEven", + "signed_byte_p_int", + "zf_spec", + //"b_xor", + //"logand_int", + //"not_bit", + //"floor2", + ]; + for name in linearize_functions { + linearize_function(&mut arch, name, &mut symtab)?; + } + + let use_model_reg_init = true; + let iarch = initialize_architecture( + &mut arch, + symtab, + type_info, + &isa_config, + AssertionMode::Optimistic, + use_model_reg_init, + ); + + // Setup machine code. + let machine_code = vec![0x4c, 0x01, 0xea]; + println!("machine code = {:02x?}", machine_code); + + // ISLA trace. + let paths = trace_opcode(&machine_code, &iarch)?; + + // Dump. + for (i, events) in paths.iter().enumerate() { + let filename = format!("trace{i:04}.out"); + let path = options.output_dir.join(filename); + log!(log::VERBOSE, format!("write trace to {}", path.display())); + + let file = std::fs::File::create(path)?; + write_events(&events, &iarch, file)?; + } + + log!( + log::VERBOSE, + format!("generated {} trace paths", paths.len()) + ); + + Ok(()) +} + +fn trace_opcode<'ir, B: BV>( + opcode: &Vec, + iarch: &'ir Initialized<'ir, B>, +) -> anyhow::Result>>> { + let shared_state = &&iarch.shared_state; + let symtab = &shared_state.symtab; + + let initial_checkpoint = Checkpoint::new(); + let solver_cfg = smt::Config::new(); + let solver_ctx = smt::Context::new(solver_cfg); + let mut solver = Solver::from_checkpoint(&solver_ctx, initial_checkpoint); + let memory = Memory::new(); + + // Initialization ----------------------------------------------------------- + // - run initialization function to set processor in 64-bit mode + + let init_function = zencode::encode("initialise_64_bit_mode"); + let function_id = shared_state.symtab.lookup(&init_function); + let (args, ret_ty, instrs) = shared_state.functions.get(&function_id).unwrap(); + + let task_state = TaskState::::new(); + let checkpoint = smt::checkpoint(&mut solver); + let task = LocalFrame::new(function_id, args, ret_ty, None, instrs) + .add_lets(&iarch.lets) + .add_regs(&iarch.regs) + .set_memory(memory) + .task_with_checkpoint(0, &task_state, checkpoint); + + let queue = Arc::new(SegQueue::new()); + executor::start_single( + task, + &shared_state, + &queue, + &move |_tid, _task_id, result, _shared_state, mut solver, queue| match result { + Ok((_, frame)) => { + queue.push((freeze_frame(&frame), smt::checkpoint(&mut solver))); + } + Err(err) => panic!("Initialisation failed: {:?}", err), + }, + ); + assert_eq!(queue.len(), 1); + let (frame, checkpoint) = queue.pop().expect("pop failed"); + + let mut solver = Solver::from_checkpoint(&solver_ctx, checkpoint); + + // Initialize registers ----------------------------------------------------- + // - set symbolic values for all general-purpose registers + + let mut local_frame = executor::unfreeze_frame(&frame); + for (n, ty) in &shared_state.registers { + // Only handle general-purpose registers. + if let Ty::Bits(bits) = ty { + let var = solver.fresh(); + solver.add(smtlib::Def::DeclareConst(var, smtlib::Ty::BitVec(*bits))); + let val = Val::Symbolic(var); + local_frame.regs_mut().assign(*n, val, shared_state); + } + } + + let frame = freeze_frame(&local_frame); + + // Setup memory ------------------------------------------------------------- + + let mut local_frame = unfreeze_frame(&frame); + + const INIT_PC: Address = 0x401000; + local_frame + .memory_mut() + .add_symbolic_code_region(INIT_PC..INIT_PC + 0x10000); + + let memory_var = solver.fresh(); + solver.add(smtlib::Def::DeclareConst( + memory_var, + smtlib::Ty::Array( + Box::new(smtlib::Ty::BitVec(64)), + Box::new(smtlib::Ty::BitVec(8)), + ), + )); + + let memory_client_info: Box> = + Box::new(SeqMemory { memory_var }); + local_frame.memory_mut().set_client_info(memory_client_info); + + let frame = freeze_frame(&local_frame); + + // Set initial program counter ---------------------------------------------- + + let local_frame = unfreeze_frame(&frame); + + let pc_name = zencode::encode("rip"); + let pc_id = symtab.lookup(&pc_name); + let pc = local_frame.regs().get_last_if_initialized(pc_id).unwrap(); + + solver.add(smtlib::Def::Assert(smtlib::Exp::Eq( + Box::new(smt_value(pc).unwrap()), + Box::new(smtlib::Exp::Bits64(B64::from_u64(INIT_PC))), + ))); + + let frame = freeze_frame(&local_frame); + + // Setup opcode ------------------------------------------------------------- + + let local_frame = unfreeze_frame(&frame); + + let read_val = local_frame + .memory() + .read( + Val::Unit, /* read_kind */ + pc.clone(), + Val::I128(opcode.len() as i128), + &mut solver, + false, + ReadOpts::ifetch(), + ) + .unwrap(); + + let opcode_var = solver.fresh(); + solver.add(smtlib::Def::DeclareConst( + opcode_var, + smtlib::Ty::BitVec(8 * opcode.len() as u32), + )); + solver.add(smtlib::Def::Assert(smtlib::Exp::Eq( + Box::new(smtlib::Exp::Var(opcode_var)), + Box::new(smt_bytes(opcode)), + ))); + + let read_exp = smt_value(&read_val).unwrap(); + solver.add(smtlib::Def::Assert(smtlib::Exp::Eq( + Box::new(smtlib::Exp::Var(opcode_var)), + Box::new(read_exp), + ))); + + let frame = freeze_frame(&local_frame); + + // Debug dump --------------------------------------------------------------- + + assert_eq!(solver.check_sat(), smt::SmtResult::Sat); + let checkpoint = smt::checkpoint(&mut solver); + dump_checkpoint(&checkpoint, iarch)?; + + // Execute fetch and decode ------------------------------------------------- + + let local_frame = unfreeze_frame(&frame); + + local_frame.memory().log(); + + let run_instruction_function = zencode::encode("x86_fetch_decode_execute"); + let function_id = shared_state.symtab.lookup(&run_instruction_function); + let (args, ret_ty, instrs) = shared_state.functions.get(&function_id).unwrap(); + + let task_state = TaskState::::new(); + let task = local_frame + .new_call(function_id, args, ret_ty, None, instrs) + .task_with_checkpoint(1, &task_state, checkpoint); + + let num_threads = 1; + let queue = Arc::new(SegQueue::new()); + executor::start_multi( + num_threads, + None, + vec![task], + shared_state, + queue.clone(), + &executor::trace_collector, + ); + + let mut paths = Vec::new(); + loop { + match queue.pop() { + Some(Ok((_, mut events))) => { + // simplify::hide_initialization(&mut events); + simplify::remove_extra_register_fields(&mut events); + simplify::remove_repeated_register_reads(&mut events); + simplify::remove_unused_register_assumptions(&mut events); + simplify::remove_unused(&mut events); + simplify::propagate_forwards_used_once(&mut events); + simplify::commute_extract(&mut events); + simplify::eval(&mut events); + + let events: Vec> = events.drain(..).rev().collect(); + paths.push(events); + } + + // Error during execution + Some(Err(err)) => { + let msg = format!("{}", err); + eprintln!( + "{}", + err.source_loc().message::( + None, + shared_state.symtab.files(), + &msg, + true, + true + ) + ); + anyhow::bail!("{}", err); + } + // Empty queue + None => break, + } + } + + Ok(paths) +} + +#[derive(Debug, Clone)] +struct SeqMemory { + memory_var: Sym, +} + +impl isla_lib::memory::MemoryCallbacks for SeqMemory { + fn symbolic_read( + &self, + regions: &[isla_lib::memory::Region], + solver: &mut Solver, + value: &Val, + _read_kind: &Val, + address: &Val, + bytes: u32, + _tag: &Option>, + opts: &ReadOpts, + ) { + use isla_lib::smt::smtlib::{Def, Exp}; + + let read_exp = smt_value(value) + .unwrap_or_else(|err| panic!("Bad memory read value {:?}: {}", value, err)); + let addr_exp = smt_value(address) + .unwrap_or_else(|err| panic!("Bad read address value {:?}: {}", address, err)); + let read_prop = Exp::Eq( + Box::new(read_exp.clone()), + Box::new(smt_read_exp(self.memory_var, &addr_exp, bytes as u64)), + ); + let kind = if opts.is_ifetch { + SmtKind::ReadInstr + } else if opts.is_exclusive { + // We produce a dummy read so that failed store exclusives still get address + // constraints, but the memory must be writable. + SmtKind::WriteData + } else { + SmtKind::ReadData + }; + let address_constraint = + isla_lib::memory::smt_address_constraint(regions, &addr_exp, bytes, kind, solver, None); + + let full_constraint = Exp::And(Box::new(address_constraint), Box::new(read_prop)); + + solver.add(Def::Assert(full_constraint)); + } + + fn symbolic_write( + &mut self, + regions: &[isla_lib::memory::Region], + solver: &mut Solver, + _value: Sym, + _read_kind: &Val, + address: &Val, + data: &Val, + bytes: u32, + _tag: &Option>, + _opts: &smt::WriteOpts, + ) { + use isla_lib::smt::smtlib::{Def, Exp}; + + let data_exp = smt_value(data) + .unwrap_or_else(|err| panic!("Bad memory write value {:?}: {}", data, err)); + let addr_exp = smt_value(address) + .unwrap_or_else(|err| panic!("Bad write address value {:?}: {}", address, err)); + // TODO: endianness? + let mut mem_exp = Exp::Store( + Box::new(Exp::Var(self.memory_var)), + Box::new(addr_exp.clone()), + Box::new(Exp::Extract(7, 0, Box::new(data_exp.clone()))), + ); + for i in 1..bytes { + mem_exp = Exp::Store( + Box::new(mem_exp), + Box::new(Exp::Bvadd( + Box::new(addr_exp.clone()), + Box::new(bits64(i as u64, 64)), + )), + Box::new(Exp::Extract(i * 8 + 7, i * 8, Box::new(data_exp.clone()))), + ) + } + self.memory_var = solver.fresh(); + solver.add(Def::DefineConst(self.memory_var, mem_exp)); + let kind = SmtKind::WriteData; + let address_constraint = + isla_lib::memory::smt_address_constraint(regions, &addr_exp, bytes, kind, solver, None); + solver.add(Def::Assert(address_constraint)); + } + + fn symbolic_write_tag( + &mut self, + _regions: &[isla_lib::memory::Region], + _solver: &mut Solver, + _value: Sym, + _write_kind: &Val, + _address: &Val, + _tag: &Val, + ) { + } +} + +fn smt_value(v: &Val) -> Result, ExecError> { + isla_lib::primop_util::smt_value(v, SourceLoc::unknown()) +} + +fn smt_read_exp(memory: Sym, addr_exp: &smtlib::Exp, bytes: u64) -> smtlib::Exp { + use smtlib::Exp; + // TODO: endianness? + let mut mem_exp = Exp::Select(Box::new(Exp::Var(memory)), Box::new(addr_exp.clone())); + for i in 1..bytes { + mem_exp = Exp::Concat( + Box::new(Exp::Select( + Box::new(Exp::Var(memory)), + Box::new(Exp::Bvadd( + Box::new(addr_exp.clone()), + Box::new(bits64(i as u64, 64)), + )), + )), + Box::new(mem_exp), + ) + } + mem_exp +} + +fn smt_bytes(bytes: &Vec) -> smtlib::Exp { + let mut bits = Vec::with_capacity(bytes.len() * 8); + for byte in bytes { + for i in 0..8 { + bits.push((byte >> i) & 1 == 1); + } + } + smtlib::Exp::Bits(bits) +} + +fn dump_checkpoint<'ir, B: BV>( + checkpoint: &Checkpoint, + iarch: &'ir Initialized<'ir, B>, +) -> anyhow::Result<()> { + if let Some(trace) = checkpoint.trace() { + let events: Vec> = trace.to_vec().into_iter().cloned().collect(); + write_events_to_stdout(&events, iarch)?; + } + Ok(()) +} + +/// Write ISLA trace events to stdout. +fn write_events_to_stdout<'ir, B: BV>( + events: &Vec>, + iarch: &'ir Initialized<'ir, B>, +) -> anyhow::Result<()> { + let stdout = std::io::stdout().lock(); + write_events(events, iarch, stdout) +} + +fn write_events<'ir, B: BV>( + events: &Vec>, + iarch: &'ir Initialized<'ir, B>, + w: impl Sized + Write, +) -> anyhow::Result<()> { + let mut handle = BufWriter::with_capacity(5 * usize::pow(2, 20), w); + let write_opts = WriteOpts::default(); + simplify::write_events_with_opts(&mut handle, &events, &iarch.shared_state, &write_opts) + .unwrap(); + handle.flush().unwrap(); + + Ok(()) +} + +/// Parse Jib IR. +fn parse_ir<'a, 'input, B: BV>( + contents: &'input str, + symtab: &'a mut Symtab<'input>, +) -> anyhow::Result>> { + match ir_parser::IrParser::new().parse(symtab, new_ir_lexer(&contents)) { + Ok(ir) => Ok(ir), + Err(_) => Err(anyhow::Error::msg("bad")), + } +} + +fn linearize_function<'ir, B: BV>( + arch: &mut Vec>, + name: &str, + symtab: &mut Symtab<'ir>, +) -> anyhow::Result<()> { + log!(log::VERBOSE, format!("linearize function {}", name)); + + // Lookup function name. + let target = match symtab.get(&zencode::encode(name)) { + Some(t) => t, + None => anyhow::bail!("function {} could not be found", name), + }; + + // Find signature. + let (_args, ret) = lookup_signature(arch, target)?; + + // Rewrite. + for def in arch.iter_mut() { + if let Def::Fn(f, _, body) = def { + if *f == target { + let rewritten = linearize::linearize(body.to_vec(), &ret, symtab); + *body = rewritten; + } + } + } + + Ok(()) +} + +fn lookup_signature( + arch: &Vec>, + target: Name, +) -> anyhow::Result<(Vec>, Ty)> { + for def in arch { + match def { + Def::Val(f, args, ret) if *f == target => return Ok((args.clone(), ret.clone())), + _ => (), + } + } + anyhow::bail!("could not find type signature") +} From feaa68804dccfe9b9e8c90b10ebb32634542087f Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Fri, 2 Feb 2024 10:57:10 -0500 Subject: [PATCH 62/73] switch back to add rule --- cranelift/codegen/src/isa/aarch64/inst.isle | 8 ++-- .../codegen/src/isa/aarch64/inst_specs.isle | 14 ++++-- .../isle/veri/veri_engine/src/bin/isaspec.rs | 47 ++++++++++--------- cranelift/isle/veri/veri_engine/tests/veri.rs | 8 ++-- 4 files changed, 41 insertions(+), 36 deletions(-) diff --git a/cranelift/codegen/src/isa/aarch64/inst.isle b/cranelift/codegen/src/isa/aarch64/inst.isle index 5ef438c0007e..3ae47438a473 100644 --- a/cranelift/codegen/src/isa/aarch64/inst.isle +++ b/cranelift/codegen/src/isa/aarch64/inst.isle @@ -2030,13 +2030,13 @@ ;; (if (<= t 32) ;; (conv_to 64 (bvshl (extract 31 0 a) (bvand (bvsub (int2bv 32 32) #x00000001) (extract 31 0 b)))) ;; (bvshl a (bvand (bvsub (int2bv 64 64) #x0000000000000001) b)))) - ((ALUOp.And) + ((ALUOp.Add) (if (<= ty 32) - (conv_to 64 (bvand (extract 31 0 a) (extract 31 0 b))) - (bvand a b)))))) + (conv_to 64 (bvadd (extract 31 0 a) (extract 31 0 b))) + (bvadd a b)))))) (require ; (or (= op (ALUOp.Lsr)) (= op (ALUOp.Asr)) (= op (ALUOp.Lsl))) - (or (= op (ALUOp.And))) + (or (= op (ALUOp.Add))) ; (or (= ty 8) (= ty 16) (= ty 32) (= ty 64)) (or (= ty 64)) ) diff --git a/cranelift/codegen/src/isa/aarch64/inst_specs.isle b/cranelift/codegen/src/isa/aarch64/inst_specs.isle index ab4756c9d905..c094c4ca0e3a 100644 --- a/cranelift/codegen/src/isa/aarch64/inst_specs.isle +++ b/cranelift/codegen/src/isa/aarch64/inst_specs.isle @@ -1,8 +1,12 @@ (spec (MInst.AluRRR alu_op size rd rn rm) (provide - (= rn v544) - (= rm v546) - (= v550 (bvand (extract 63 0 v544) (extract 63 0 v546))) - (= rd v550)) - (require (= alu_op (ALUOp.And)) (= size (OperandSize.Size64)))) + (= rn v536) + (= rm v538) + (= + v581 + (bvadd + (extract 63 0 (zero_ext 128 (extract 63 0 v536))) + (extract 63 0 (zero_ext 128 (extract 63 0 v538))))) + (= rd v581)) + (require (= alu_op (ALUOp.Add)) (= size (OperandSize.Size64)))) diff --git a/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs b/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs index 1241b0c125ca..09c2a09736de 100644 --- a/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs +++ b/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs @@ -77,29 +77,30 @@ fn main() -> anyhow::Result<()> { fn define() -> Vec { // ALUOp let alu_ops = vec![ - //ALUOp::Add, // 128-bit ops - //ALUOp::Sub, // 128-bit ops - //ALUOp::Orr, - //ALUOp::OrrNot, - ALUOp::And, - //ALUOp::AndNot, - //ALUOp::Eor, - //ALUOp::EorNot, - //ALUOp::Lsr, - //ALUOp::Asr, - //ALUOp::Lsl, - //ALUOp::AndS, // 2 code paths - //ALUOp::AddS, - //ALUOp::SubS, - //ALUOp::SMulH, - //ALUOp::UMulH, - //ALUOp::SDiv, - //ALUOp::UDiv, - //ALUOp::RotR, - //ALUOp::Adc, - //ALUOp::AdcS, - //ALUOp::Sbc, - //ALUOp::SbcS, + ALUOp::Add, // 128-bit ops + + //ALUOp::Sub, // 128-bit ops + //ALUOp::Orr, + //ALUOp::OrrNot, + //ALUOp::And, + //ALUOp::AndNot, + //ALUOp::Eor, + //ALUOp::EorNot, + //ALUOp::Lsr, + //ALUOp::Asr, + //ALUOp::Lsl, + //ALUOp::AndS, // 2 code paths + //ALUOp::AddS, + //ALUOp::SubS, + //ALUOp::SMulH, + //ALUOp::UMulH, + //ALUOp::SDiv, + //ALUOp::UDiv, + //ALUOp::RotR, + //ALUOp::Adc, + //ALUOp::AdcS, + //ALUOp::Sbc, + //ALUOp::SbcS, ]; // AluRRR diff --git a/cranelift/isle/veri/veri_engine/tests/veri.rs b/cranelift/isle/veri/veri_engine/tests/veri.rs index deb83d7a8690..91253b7e0ebe 100644 --- a/cranelift/isle/veri/veri_engine/tests/veri.rs +++ b/cranelift/isle/veri/veri_engine/tests/veri.rs @@ -3201,15 +3201,15 @@ fn test_broken_imm_udiv_cve_underlying_32() { } // ISA spec test: -// 1. and_alu_rrr lowers and to alu_rrr +// 1. add_alu_rrr lowers and to alu_rrr // 2. alu_rrr lowers to MInst.AluRRR #[test] -fn test_named_and_reg_alu_rrr() { +fn test_named_add_alu_rrr() { run_and_retry(|| { test_aarch64_rule_with_lhs_termname_simple( - "and_reg_alu_rrr", - "and_reg", + "add_alu_rrr", + "add", vec![(Bitwidth::I64, VerificationResult::Success)], ) }) From 95f5c4a8be1ccff1bcf874b72ed236248dca3f00 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Sun, 18 Feb 2024 13:22:58 -0500 Subject: [PATCH 63/73] restore imp case in spec_op_to_expr --- cranelift/isle/veri/veri_engine/src/annotations.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/cranelift/isle/veri/veri_engine/src/annotations.rs b/cranelift/isle/veri/veri_engine/src/annotations.rs index 4e4dafef2988..c796dc1d7a7d 100644 --- a/cranelift/isle/veri/veri_engine/src/annotations.rs +++ b/cranelift/isle/veri/veri_engine/src/annotations.rs @@ -141,6 +141,7 @@ fn spec_op_to_expr(s: &SpecOp, args: &Vec, pos: &Pos, env: &ParsingEnv SpecOp::Lte => binop(|x, y| Expr::Lte(x, y), args, pos, env), SpecOp::Gt => binop(|x, y| Expr::Lt(y, x), args, pos, env), SpecOp::Gte => binop(|x, y| Expr::Lte(y, x), args, pos, env), + SpecOp::Imp => binop(|x, y| Expr::Imp(x, y), args, pos, env), SpecOp::BVAnd => binop(|x, y| Expr::BVAnd(x, y), args, pos, env), SpecOp::BVOr => binop(|x, y| Expr::BVOr(x, y), args, pos, env), SpecOp::BVXor => binop(|x, y| Expr::BVXor(x, y), args, pos, env), From 8c95834cbb82902db8d5289a725a4421b82f5b7d Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Sun, 18 Feb 2024 14:30:49 -0500 Subject: [PATCH 64/73] revert changes to aarch64/inst.isle --- cranelift/codegen/src/isa/aarch64/inst.isle | 76 +++++++-------------- 1 file changed, 25 insertions(+), 51 deletions(-) diff --git a/cranelift/codegen/src/isa/aarch64/inst.isle b/cranelift/codegen/src/isa/aarch64/inst.isle index 3ae47438a473..fb497367f79b 100644 --- a/cranelift/codegen/src/isa/aarch64/inst.isle +++ b/cranelift/codegen/src/isa/aarch64/inst.isle @@ -2015,37 +2015,26 @@ dst)) ;; Helper for emitting `MInst.AluRRR` instructions. -(spec (alu_rrr op ty a b) +(spec (alu_rrr op t a b) (provide - (= result (switch op - ;; ((ALUOp.Lsr) - ;; (if (<= t 32) - ;; (conv_to 64 (bvlshr (extract 31 0 a) (bvand (bvsub (int2bv 32 32) #x00000001) (extract 31 0 b)))) - ;; (bvlshr a (bvand (bvsub (int2bv 64 64) #x0000000000000001) b)))) - ;; ((ALUOp.Asr) - ;; (if (<= t 32) - ;; (conv_to 64 (bvashr (extract 31 0 a) (bvand (bvsub (int2bv 32 32) #x00000001) (extract 31 0 b)))) - ;; (bvashr a (bvand (bvsub (int2bv 64 64) #x0000000000000001) b)))) - ;; ((ALUOp.Lsl) - ;; (if (<= t 32) - ;; (conv_to 64 (bvshl (extract 31 0 a) (bvand (bvsub (int2bv 32 32) #x00000001) (extract 31 0 b)))) - ;; (bvshl a (bvand (bvsub (int2bv 64 64) #x0000000000000001) b)))) - ((ALUOp.Add) - (if (<= ty 32) - (conv_to 64 (bvadd (extract 31 0 a) (extract 31 0 b))) - (bvadd a b)))))) + (= result (switch op + ((ALUOp.Lsr) + (if (<= t 32) + (conv_to 64 (bvlshr (extract 31 0 a) (bvand (bvsub (int2bv 32 32) #x00000001) (extract 31 0 b)))) + (bvlshr a (bvand (bvsub (int2bv 64 64) #x0000000000000001) b)))) + ((ALUOp.Asr) + (if (<= t 32) + (conv_to 64 (bvashr (extract 31 0 a) (bvand (bvsub (int2bv 32 32) #x00000001) (extract 31 0 b)))) + (bvashr a (bvand (bvsub (int2bv 64 64) #x0000000000000001) b)))) + ((ALUOp.Lsl) + (if (<= t 32) + (conv_to 64 (bvshl (extract 31 0 a) (bvand (bvsub (int2bv 32 32) #x00000001) (extract 31 0 b)))) + (bvshl a (bvand (bvsub (int2bv 64 64) #x0000000000000001) b))))))) (require - ; (or (= op (ALUOp.Lsr)) (= op (ALUOp.Asr)) (= op (ALUOp.Lsl))) - (or (= op (ALUOp.Add))) - ; (or (= ty 8) (= ty 16) (= ty 32) (= ty 64)) - (or (= ty 64)) - ) -) + (or (= op (ALUOp.Lsr)) (= op (ALUOp.Asr)) (= op (ALUOp.Lsl))) + (or (= t 8) (= t 16) (= t 32) (= t 64)))) (decl alu_rrr (ALUOp Type Reg Reg) Reg) -(instantiate alu_rrr - ((args (bv 8) Int (bv 64) (bv 64)) (ret (bv 64)) (canon (bv 64))) -) -(rule alu_rrr_emit (alu_rrr op ty src1 src2) +(rule (alu_rrr op ty src1 src2) (let ((dst WritableReg (temp_writable_reg $I64)) (_ Unit (emit (MInst.AluRRR op (operand_size ty) dst src1 src2)))) dst)) @@ -2641,22 +2630,13 @@ ;; Helpers for generating `add` instructions. (spec (add ty a b) - (provide - (= result - (if (<= ty 32) - (conv_to 64 (bvadd (extract 31 0 a) (extract 31 0 b))) - (bvadd a b))) - ) - (require - (= ty (widthof a)) - (= ty (widthof b)) - ) -) + (provide + (= result + (if (<= ty 32) + (conv_to 64 (bvadd (extract 31 0 a) (extract 31 0 b))) + (bvadd a b))))) (decl add (Type Reg Reg) Reg) -(instantiate add - ((args Int (bv 64) (bv 64)) (ret (bv 64)) (canon (bv 64))) -) -(rule add_alu_rrr (add ty x y) (alu_rrr (ALUOp.Add) ty x y)) +(rule (add ty x y) (alu_rrr (ALUOp.Add) ty x y)) (spec (add_imm ty a b) (provide @@ -3170,15 +3150,9 @@ (if (<= ty 32) (conv_to 64 (bvand (extract 31 0 a) (extract 31 0 b))) (bvand a b)))) - (require - ; (or (= ty 8) (= ty 16) (= ty 32) (= ty 64)) - (= ty 64) - )) + (require (or (= ty 8) (= ty 16) (= ty 32) (= ty 64)))) (decl and_reg (Type Reg Reg) Reg) -(instantiate and_reg - ((args Int (bv 64) (bv 64)) (ret (bv 64)) (canon (bv 64))) -) -(rule and_reg_alu_rrr (and_reg ty x y) (alu_rrr (ALUOp.And) ty x y)) +(rule (and_reg ty x y) (alu_rrr (ALUOp.And) ty x y)) (spec (and_imm ty x y) (provide From d1e50b02c8211b1903ab37da9f1539924103f918 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Sun, 18 Feb 2024 14:31:03 -0500 Subject: [PATCH 65/73] remove debug print in widen to register width --- cranelift/isle/veri/veri_engine/src/solver.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/cranelift/isle/veri/veri_engine/src/solver.rs b/cranelift/isle/veri/veri_engine/src/solver.rs index 2baf12cc1d11..84fda93315f9 100644 --- a/cranelift/isle/veri/veri_engine/src/solver.rs +++ b/cranelift/isle/veri/veri_engine/src/solver.rs @@ -457,10 +457,6 @@ impl SolverCtx { narrow_decl: SExpr, name: Option, ) -> SExpr { - println!( - "widen: tyvar={tyvar:?} narrow_width={narrow_width:?} name={name:?} bitwidth={}", - self.bitwidth - ); let width = self.bitwidth.checked_sub(narrow_width).unwrap(); if width > 0 { let mut narrow_name = format!("narrow__{}", tyvar); From cfd78d8466b5cc21e0f0e2b779a7b6d0347489ca Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Sun, 18 Feb 2024 17:37:08 -0500 Subject: [PATCH 66/73] wip --- cranelift/codegen/src/isa/aarch64/inst.isle | 9 +- .../codegen/src/isa/aarch64/inst_specs.isle | 141 ++++++++++++++++-- cranelift/codegen/src/prelude_lower.isle | 2 +- .../isle/veri/veri_engine/src/bin/isaspec.rs | 47 +++--- 4 files changed, 163 insertions(+), 36 deletions(-) diff --git a/cranelift/codegen/src/isa/aarch64/inst.isle b/cranelift/codegen/src/isa/aarch64/inst.isle index fb497367f79b..a8713eee9485 100644 --- a/cranelift/codegen/src/isa/aarch64/inst.isle +++ b/cranelift/codegen/src/isa/aarch64/inst.isle @@ -2032,9 +2032,14 @@ (bvshl a (bvand (bvsub (int2bv 64 64) #x0000000000000001) b))))))) (require (or (= op (ALUOp.Lsr)) (= op (ALUOp.Asr)) (= op (ALUOp.Lsl))) - (or (= t 8) (= t 16) (= t 32) (= t 64)))) + ;(or (= t 8) (= t 16) (= t 32) (= t 64))) + (or (= t 64))) + ) (decl alu_rrr (ALUOp Type Reg Reg) Reg) -(rule (alu_rrr op ty src1 src2) +(instantiate alu_rrr + ((args (bv 8) Int (bv 64) (bv 64)) (ret (bv 64)) (canon (bv 64))) +) +(rule alu_rrr_emit (alu_rrr op ty src1 src2) (let ((dst WritableReg (temp_writable_reg $I64)) (_ Unit (emit (MInst.AluRRR op (operand_size ty) dst src1 src2)))) dst)) diff --git a/cranelift/codegen/src/isa/aarch64/inst_specs.isle b/cranelift/codegen/src/isa/aarch64/inst_specs.isle index c094c4ca0e3a..44bcfd597a14 100644 --- a/cranelift/codegen/src/isa/aarch64/inst_specs.isle +++ b/cranelift/codegen/src/isa/aarch64/inst_specs.isle @@ -1,12 +1,135 @@ (spec (MInst.AluRRR alu_op size rd rn rm) (provide - (= rn v536) - (= rm v538) - (= - v581 - (bvadd - (extract 63 0 (zero_ext 128 (extract 63 0 v536))) - (extract 63 0 (zero_ext 128 (extract 63 0 v538))))) - (= rd v581)) - (require (= alu_op (ALUOp.Add)) (= size (OperandSize.Size64)))) + (= result #b1) + (=> + (and (= alu_op (ALUOp.Lsr)) (= size (OperandSize.Size64))) + (and + (= rm v535) + (= v537 (zero_ext 128 (extract 63 0 v535))) + (= rn v541) + (= + v544 + (bvlshr + (extract 63 0 v541) + (extract + 63 + 0 + (sign_ext + 128 + (extract + 63 + 0 + (if + (bvslt + (bvsrem + v537 + (concat #x0000000000000000 #x0000000000000040)) + (concat #x0000000000000000 #x0000000000000000)) + (if + (bvslt + (concat #x0000000000000000 #x0000000000000040) + (concat #x0000000000000000 #x0000000000000000)) + (bvsub + (bvsrem + v537 + (concat #x0000000000000000 #x0000000000000040)) + (concat #x0000000000000000 #x0000000000000040)) + (bvadd + (bvsrem + v537 + (concat #x0000000000000000 #x0000000000000040)) + (concat #x0000000000000000 #x0000000000000040))) + (bvsrem + v537 + (concat #x0000000000000000 #x0000000000000040)))))))) + (= rd v544))) + (=> + (and (= alu_op (ALUOp.Asr)) (= size (OperandSize.Size64))) + (and + (= rm v535) + (= v537 (zero_ext 128 (extract 63 0 v535))) + (= rn v541) + (= + v544 + (bvashr + (extract 63 0 v541) + (extract + 63 + 0 + (sign_ext + 128 + (extract + 63 + 0 + (if + (bvslt + (bvsrem + v537 + (concat #x0000000000000000 #x0000000000000040)) + (concat #x0000000000000000 #x0000000000000000)) + (if + (bvslt + (concat #x0000000000000000 #x0000000000000040) + (concat #x0000000000000000 #x0000000000000000)) + (bvsub + (bvsrem + v537 + (concat #x0000000000000000 #x0000000000000040)) + (concat #x0000000000000000 #x0000000000000040)) + (bvadd + (bvsrem + v537 + (concat #x0000000000000000 #x0000000000000040)) + (concat #x0000000000000000 #x0000000000000040))) + (bvsrem + v537 + (concat #x0000000000000000 #x0000000000000040)))))))) + (= rd v544))) + (=> + (and (= alu_op (ALUOp.Lsl)) (= size (OperandSize.Size64))) + (and + (= rm v535) + (= v537 (zero_ext 128 (extract 63 0 v535))) + (= rn v541) + (= + v544 + (bvshl + (extract 63 0 v541) + (extract + 63 + 0 + (sign_ext + 128 + (extract + 63 + 0 + (if + (bvslt + (bvsrem + v537 + (concat #x0000000000000000 #x0000000000000040)) + (concat #x0000000000000000 #x0000000000000000)) + (if + (bvslt + (concat #x0000000000000000 #x0000000000000040) + (concat #x0000000000000000 #x0000000000000000)) + (bvsub + (bvsrem + v537 + (concat #x0000000000000000 #x0000000000000040)) + (concat #x0000000000000000 #x0000000000000040)) + (bvadd + (bvsrem + v537 + (concat #x0000000000000000 #x0000000000000040)) + (concat #x0000000000000000 #x0000000000000040))) + (bvsrem + v537 + (concat #x0000000000000000 #x0000000000000040)))))))) + (= rd v544)))) + (require + (or + (and (= alu_op (ALUOp.Lsr)) (= size (OperandSize.Size64))) + (and (= alu_op (ALUOp.Asr)) (= size (OperandSize.Size64))) + (and (= alu_op (ALUOp.Lsl)) (= size (OperandSize.Size64)))))) diff --git a/cranelift/codegen/src/prelude_lower.isle b/cranelift/codegen/src/prelude_lower.isle index 7bb52cd6908f..a1a4a42865b7 100644 --- a/cranelift/codegen/src/prelude_lower.isle +++ b/cranelift/codegen/src/prelude_lower.isle @@ -335,7 +335,7 @@ (decl emit (MInst) Unit) (extern constructor emit emit) ; TODO(mbm): what is the right spec for emit? -(spec (emit inst) (provide true)) +(spec (emit inst) (provide (= result #b1))) ;; Sink an instruction. ;; diff --git a/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs b/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs index 09c2a09736de..5e5b05ee709d 100644 --- a/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs +++ b/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs @@ -77,30 +77,29 @@ fn main() -> anyhow::Result<()> { fn define() -> Vec { // ALUOp let alu_ops = vec![ - ALUOp::Add, // 128-bit ops - - //ALUOp::Sub, // 128-bit ops - //ALUOp::Orr, - //ALUOp::OrrNot, - //ALUOp::And, - //ALUOp::AndNot, - //ALUOp::Eor, - //ALUOp::EorNot, - //ALUOp::Lsr, - //ALUOp::Asr, - //ALUOp::Lsl, - //ALUOp::AndS, // 2 code paths - //ALUOp::AddS, - //ALUOp::SubS, - //ALUOp::SMulH, - //ALUOp::UMulH, - //ALUOp::SDiv, - //ALUOp::UDiv, - //ALUOp::RotR, - //ALUOp::Adc, - //ALUOp::AdcS, - //ALUOp::Sbc, - //ALUOp::SbcS, + //ALUOp::Add, + //ALUOp::Sub, + //ALUOp::Orr, + //ALUOp::OrrNot, + //ALUOp::And, + //ALUOp::AndNot, + //ALUOp::Eor, + //ALUOp::EorNot, + ALUOp::Lsr, + ALUOp::Asr, + ALUOp::Lsl, + //ALUOp::AndS, // 2 code paths + //ALUOp::AddS, + //ALUOp::SubS, + //ALUOp::SMulH, + //ALUOp::UMulH, + //ALUOp::SDiv, + //ALUOp::UDiv, + //ALUOp::RotR, + //ALUOp::Adc, + //ALUOp::AdcS, + //ALUOp::Sbc, + //ALUOp::SbcS, ]; // AluRRR From eee9cffdc1548d5b8d36070557eb69fc5f2ebcfb Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Sun, 18 Feb 2024 18:58:13 -0500 Subject: [PATCH 67/73] fix build --- cranelift/codegen/src/isa/riscv64/inst/mod.rs | 2 +- cranelift/codegen/src/machinst/isle.rs | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/cranelift/codegen/src/isa/riscv64/inst/mod.rs b/cranelift/codegen/src/isa/riscv64/inst/mod.rs index 4c10191eccfc..8d30451a972c 100644 --- a/cranelift/codegen/src/isa/riscv64/inst/mod.rs +++ b/cranelift/codegen/src/isa/riscv64/inst/mod.rs @@ -9,7 +9,7 @@ use crate::binemit::{Addend, CodeOffset, Reloc}; pub use crate::ir::condcodes::IntCC; use crate::ir::types::{self, F32, F64, I128, I16, I32, I64, I8, I8X16, R32, R64}; -pub use crate::ir::{ExternalName, MemFlags, Opcode, SourceLoc, Type, ValueLabel}; +pub use crate::ir::{ExternalName, MemFlags, Opcode, Type}; use crate::isa::{CallConv, FunctionAlignment}; use crate::machinst::*; use crate::{settings, CodegenError, CodegenResult}; diff --git a/cranelift/codegen/src/machinst/isle.rs b/cranelift/codegen/src/machinst/isle.rs index 13c1792314b5..c3be76f0b070 100644 --- a/cranelift/codegen/src/machinst/isle.rs +++ b/cranelift/codegen/src/machinst/isle.rs @@ -7,12 +7,14 @@ use std::cell::Cell; pub use super::MachLabel; use super::RetPair; pub use crate::ir::{ - condcodes, condcodes::CondCode, dynamic_to_fixed, Constant, DynamicStackSlot, ExternalName, - FuncRef, GlobalValue, Immediate, SigRef, StackSlot, + condcodes, condcodes::CondCode, dynamic_to_fixed, ArgumentExtension, Constant, + DynamicStackSlot, ExternalName, FuncRef, GlobalValue, Immediate, SigRef, StackSlot, }; +pub use crate::isa::unwind::UnwindInst; pub use crate::isa::TargetIsa; pub use crate::machinst::{ - ABIArg, ABIArgSlot, Lower, LowerBackend, RealReg, Reg, RelocDistance, Sig, VCodeInst, Writable, + ABIArg, ABIArgSlot, InputSourceInst, Lower, LowerBackend, RealReg, Reg, RelocDistance, Sig, + VCodeInst, Writable, }; pub use crate::settings::TlsModel; From 2100e745c66b2aa78c4b12ef342741acfaec2695 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Sun, 18 Feb 2024 20:37:12 -0500 Subject: [PATCH 68/73] isaspec generates the (= result #b1) condition --- cranelift/isle/veri/veri_engine/src/bin/isaspec.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs b/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs index 5e5b05ee709d..b77f63d66092 100644 --- a/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs +++ b/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs @@ -574,7 +574,14 @@ impl<'ir, B: BV> SpecConverter<'ir, B> { .iter() .map(|c| self.case(c)) .collect::>()?; - let cond = Conditions::merge(conds); + let mut cond = Conditions::merge(conds); + + // Assert the result is fixed 1-bit vector. + // TODO(mbm): decide on verification model for MInst, or explicitly model as void or Unit + cond.provides.insert( + 0, + spec_eq(spec_var("result".to_string()), spec_const_bit_vector(1, 1)), + ); let spec = Spec { term: spec_ident(cfg.term.clone()), From 106d01ef89974d01e948f0db527c8a35bcea07d9 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Sun, 18 Feb 2024 20:58:42 -0500 Subject: [PATCH 69/73] use different prefixes for each instruction case --- .../codegen/src/isa/aarch64/inst_specs.isle | 60 +++++++++---------- .../isle/veri/veri_engine/src/bin/isaspec.rs | 14 ++++- 2 files changed, 41 insertions(+), 33 deletions(-) diff --git a/cranelift/codegen/src/isa/aarch64/inst_specs.isle b/cranelift/codegen/src/isa/aarch64/inst_specs.isle index 44bcfd597a14..4dc7a881aa4c 100644 --- a/cranelift/codegen/src/isa/aarch64/inst_specs.isle +++ b/cranelift/codegen/src/isa/aarch64/inst_specs.isle @@ -5,13 +5,13 @@ (=> (and (= alu_op (ALUOp.Lsr)) (= size (OperandSize.Size64))) (and - (= rm v535) - (= v537 (zero_ext 128 (extract 63 0 v535))) - (= rn v541) + (= rm v0_535) + (= v0_537 (zero_ext 128 (extract 63 0 v0_535))) + (= rn v0_541) (= - v544 + v0_544 (bvlshr - (extract 63 0 v541) + (extract 63 0 v0_541) (extract 63 0 @@ -23,7 +23,7 @@ (if (bvslt (bvsrem - v537 + v0_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000000)) (if @@ -32,28 +32,28 @@ (concat #x0000000000000000 #x0000000000000000)) (bvsub (bvsrem - v537 + v0_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000040)) (bvadd (bvsrem - v537 + v0_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000040))) (bvsrem - v537 + v0_537 (concat #x0000000000000000 #x0000000000000040)))))))) - (= rd v544))) + (= rd v0_544))) (=> (and (= alu_op (ALUOp.Asr)) (= size (OperandSize.Size64))) (and - (= rm v535) - (= v537 (zero_ext 128 (extract 63 0 v535))) - (= rn v541) + (= rm v1_535) + (= v1_537 (zero_ext 128 (extract 63 0 v1_535))) + (= rn v1_541) (= - v544 + v1_544 (bvashr - (extract 63 0 v541) + (extract 63 0 v1_541) (extract 63 0 @@ -65,7 +65,7 @@ (if (bvslt (bvsrem - v537 + v1_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000000)) (if @@ -74,28 +74,28 @@ (concat #x0000000000000000 #x0000000000000000)) (bvsub (bvsrem - v537 + v1_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000040)) (bvadd (bvsrem - v537 + v1_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000040))) (bvsrem - v537 + v1_537 (concat #x0000000000000000 #x0000000000000040)))))))) - (= rd v544))) + (= rd v1_544))) (=> (and (= alu_op (ALUOp.Lsl)) (= size (OperandSize.Size64))) (and - (= rm v535) - (= v537 (zero_ext 128 (extract 63 0 v535))) - (= rn v541) + (= rm v2_535) + (= v2_537 (zero_ext 128 (extract 63 0 v2_535))) + (= rn v2_541) (= - v544 + v2_544 (bvshl - (extract 63 0 v541) + (extract 63 0 v2_541) (extract 63 0 @@ -107,7 +107,7 @@ (if (bvslt (bvsrem - v537 + v2_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000000)) (if @@ -116,18 +116,18 @@ (concat #x0000000000000000 #x0000000000000000)) (bvsub (bvsrem - v537 + v2_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000040)) (bvadd (bvsrem - v537 + v2_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000040))) (bvsrem - v537 + v2_537 (concat #x0000000000000000 #x0000000000000040)))))))) - (= rd v544)))) + (= rd v2_544)))) (require (or (and (= alu_op (ALUOp.Lsr)) (= size (OperandSize.Size64))) diff --git a/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs b/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs index b77f63d66092..90d7e9e2e1e1 100644 --- a/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs +++ b/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs @@ -572,7 +572,8 @@ impl<'ir, B: BV> SpecConverter<'ir, B> { let conds: Vec = cfg .cases .iter() - .map(|c| self.case(c)) + .enumerate() + .map(|(i, c)| self.case(i, c)) .collect::>()?; let mut cond = Conditions::merge(conds); @@ -593,8 +594,9 @@ impl<'ir, B: BV> SpecConverter<'ir, B> { Ok(spec) } - fn case(&self, case: &InstConfig) -> anyhow::Result { + fn case(&self, i: usize, case: &InstConfig) -> anyhow::Result { let mut converter = TraceConverter::new(case.clone(), &self.iarch); + converter.set_var_prefix(format!("v{i}_")); let conds = converter.convert()?; Ok(conds) } @@ -603,6 +605,7 @@ impl<'ir, B: BV> SpecConverter<'ir, B> { struct TraceConverter<'ir, B: BV> { cfg: InstConfig, iarch: &'ir Initialized<'ir, B>, + var_prefix: String, // Keep track of registers read and written in the trace. reg_reads: HashSet, @@ -618,6 +621,7 @@ impl<'ir, B: BV> TraceConverter<'ir, B> { Self { cfg: cfg.clone(), iarch, + var_prefix: "v".to_string(), reg_reads: HashSet::new(), reg_writes: HashSet::new(), @@ -626,6 +630,10 @@ impl<'ir, B: BV> TraceConverter<'ir, B> { } } + fn set_var_prefix(&mut self, prefix: String) { + self.var_prefix = prefix; + } + fn convert(&mut self) -> anyhow::Result { let inst = &self.cfg.inst; @@ -850,7 +858,7 @@ impl<'ir, B: BV> TraceConverter<'ir, B> { } fn sym(&self, s: &Sym) -> SpecExpr { - spec_var(format!("v{}", s)) + spec_var(format!("{}{}", self.var_prefix, s)) } fn infer(&self, exp: &smtlib::Exp) -> Option { From cbc07318d822ca18b6d95f7c9d08ae82eb27ab32 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Mon, 19 Feb 2024 00:01:43 -0500 Subject: [PATCH 70/73] handle the 32-bit case --- cranelift/codegen/src/isa/aarch64/inst.isle | 8 +- .../codegen/src/isa/aarch64/inst_specs.isle | 209 +++++++++++++++--- .../isle/veri/veri_engine/src/bin/isaspec.rs | 14 +- cranelift/isle/veri/veri_engine/src/lib.rs | 2 +- 4 files changed, 197 insertions(+), 36 deletions(-) diff --git a/cranelift/codegen/src/isa/aarch64/inst.isle b/cranelift/codegen/src/isa/aarch64/inst.isle index a8713eee9485..7d44bace3e79 100644 --- a/cranelift/codegen/src/isa/aarch64/inst.isle +++ b/cranelift/codegen/src/isa/aarch64/inst.isle @@ -2020,20 +2020,20 @@ (= result (switch op ((ALUOp.Lsr) (if (<= t 32) - (conv_to 64 (bvlshr (extract 31 0 a) (bvand (bvsub (int2bv 32 32) #x00000001) (extract 31 0 b)))) + (zero_ext 64 (bvlshr (extract 31 0 a) (bvand (bvsub (int2bv 32 32) #x00000001) (extract 31 0 b)))) (bvlshr a (bvand (bvsub (int2bv 64 64) #x0000000000000001) b)))) ((ALUOp.Asr) (if (<= t 32) - (conv_to 64 (bvashr (extract 31 0 a) (bvand (bvsub (int2bv 32 32) #x00000001) (extract 31 0 b)))) + (zero_ext 64 (bvashr (extract 31 0 a) (bvand (bvsub (int2bv 32 32) #x00000001) (extract 31 0 b)))) (bvashr a (bvand (bvsub (int2bv 64 64) #x0000000000000001) b)))) ((ALUOp.Lsl) (if (<= t 32) - (conv_to 64 (bvshl (extract 31 0 a) (bvand (bvsub (int2bv 32 32) #x00000001) (extract 31 0 b)))) + (zero_ext 64 (bvshl (extract 31 0 a) (bvand (bvsub (int2bv 32 32) #x00000001) (extract 31 0 b)))) (bvshl a (bvand (bvsub (int2bv 64 64) #x0000000000000001) b))))))) (require (or (= op (ALUOp.Lsr)) (= op (ALUOp.Asr)) (= op (ALUOp.Lsl))) ;(or (= t 8) (= t 16) (= t 32) (= t 64))) - (or (= t 64))) + (or (= t 32) (= t 64))) ) (decl alu_rrr (ALUOp Type Reg Reg) Reg) (instantiate alu_rrr diff --git a/cranelift/codegen/src/isa/aarch64/inst_specs.isle b/cranelift/codegen/src/isa/aarch64/inst_specs.isle index 4dc7a881aa4c..69dffeb0fb4f 100644 --- a/cranelift/codegen/src/isa/aarch64/inst_specs.isle +++ b/cranelift/codegen/src/isa/aarch64/inst_specs.isle @@ -3,15 +3,65 @@ (provide (= result #b1) (=> - (and (= alu_op (ALUOp.Lsr)) (= size (OperandSize.Size64))) + (and (= alu_op (ALUOp.Lsr)) (= size (OperandSize.Size32))) (and (= rm v0_535) - (= v0_537 (zero_ext 128 (extract 63 0 v0_535))) + (= v0_537 (zero_ext 128 (extract 31 0 v0_535))) (= rn v0_541) (= v0_544 + (zero_ext + 64 + (bvlshr + (extract 31 0 v0_541) + (extract + 31 + 0 + (sign_ext + 128 + (extract + 63 + 0 + (if + (bvslt + (bvsrem + v0_537 + (concat #x0000000000000000 #x0000000000000020)) + (concat #x0000000000000000 #x0000000000000000)) + (if + (bvslt + (concat #x0000000000000000 #x0000000000000020) + (concat #x0000000000000000 #x0000000000000000)) + (bvsub + (bvsrem + v0_537 + (concat + #x0000000000000000 + #x0000000000000020)) + (concat #x0000000000000000 #x0000000000000020)) + (bvadd + (bvsrem + v0_537 + (concat + #x0000000000000000 + #x0000000000000020)) + (concat #x0000000000000000 #x0000000000000020))) + (bvsrem + v0_537 + (concat + #x0000000000000000 + #x0000000000000020))))))))) + (= rd v0_544))) + (=> + (and (= alu_op (ALUOp.Lsr)) (= size (OperandSize.Size64))) + (and + (= rm v1_535) + (= v1_537 (zero_ext 128 (extract 63 0 v1_535))) + (= rn v1_541) + (= + v1_544 (bvlshr - (extract 63 0 v0_541) + (extract 63 0 v1_541) (extract 63 0 @@ -23,7 +73,7 @@ (if (bvslt (bvsrem - v0_537 + v1_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000000)) (if @@ -32,28 +82,78 @@ (concat #x0000000000000000 #x0000000000000000)) (bvsub (bvsrem - v0_537 + v1_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000040)) (bvadd (bvsrem - v0_537 + v1_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000040))) (bvsrem - v0_537 + v1_537 (concat #x0000000000000000 #x0000000000000040)))))))) - (= rd v0_544))) + (= rd v1_544))) + (=> + (and (= alu_op (ALUOp.Asr)) (= size (OperandSize.Size32))) + (and + (= rm v2_535) + (= v2_537 (zero_ext 128 (extract 31 0 v2_535))) + (= rn v2_541) + (= + v2_544 + (zero_ext + 64 + (bvashr + (extract 31 0 v2_541) + (extract + 31 + 0 + (sign_ext + 128 + (extract + 63 + 0 + (if + (bvslt + (bvsrem + v2_537 + (concat #x0000000000000000 #x0000000000000020)) + (concat #x0000000000000000 #x0000000000000000)) + (if + (bvslt + (concat #x0000000000000000 #x0000000000000020) + (concat #x0000000000000000 #x0000000000000000)) + (bvsub + (bvsrem + v2_537 + (concat + #x0000000000000000 + #x0000000000000020)) + (concat #x0000000000000000 #x0000000000000020)) + (bvadd + (bvsrem + v2_537 + (concat + #x0000000000000000 + #x0000000000000020)) + (concat #x0000000000000000 #x0000000000000020))) + (bvsrem + v2_537 + (concat + #x0000000000000000 + #x0000000000000020))))))))) + (= rd v2_544))) (=> (and (= alu_op (ALUOp.Asr)) (= size (OperandSize.Size64))) (and - (= rm v1_535) - (= v1_537 (zero_ext 128 (extract 63 0 v1_535))) - (= rn v1_541) + (= rm v3_535) + (= v3_537 (zero_ext 128 (extract 63 0 v3_535))) + (= rn v3_541) (= - v1_544 + v3_544 (bvashr - (extract 63 0 v1_541) + (extract 63 0 v3_541) (extract 63 0 @@ -65,7 +165,7 @@ (if (bvslt (bvsrem - v1_537 + v3_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000000)) (if @@ -74,28 +174,78 @@ (concat #x0000000000000000 #x0000000000000000)) (bvsub (bvsrem - v1_537 + v3_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000040)) (bvadd (bvsrem - v1_537 + v3_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000040))) (bvsrem - v1_537 + v3_537 (concat #x0000000000000000 #x0000000000000040)))))))) - (= rd v1_544))) + (= rd v3_544))) + (=> + (and (= alu_op (ALUOp.Lsl)) (= size (OperandSize.Size32))) + (and + (= rm v4_535) + (= v4_537 (zero_ext 128 (extract 31 0 v4_535))) + (= rn v4_541) + (= + v4_544 + (zero_ext + 64 + (bvshl + (extract 31 0 v4_541) + (extract + 31 + 0 + (sign_ext + 128 + (extract + 63 + 0 + (if + (bvslt + (bvsrem + v4_537 + (concat #x0000000000000000 #x0000000000000020)) + (concat #x0000000000000000 #x0000000000000000)) + (if + (bvslt + (concat #x0000000000000000 #x0000000000000020) + (concat #x0000000000000000 #x0000000000000000)) + (bvsub + (bvsrem + v4_537 + (concat + #x0000000000000000 + #x0000000000000020)) + (concat #x0000000000000000 #x0000000000000020)) + (bvadd + (bvsrem + v4_537 + (concat + #x0000000000000000 + #x0000000000000020)) + (concat #x0000000000000000 #x0000000000000020))) + (bvsrem + v4_537 + (concat + #x0000000000000000 + #x0000000000000020))))))))) + (= rd v4_544))) (=> (and (= alu_op (ALUOp.Lsl)) (= size (OperandSize.Size64))) (and - (= rm v2_535) - (= v2_537 (zero_ext 128 (extract 63 0 v2_535))) - (= rn v2_541) + (= rm v5_535) + (= v5_537 (zero_ext 128 (extract 63 0 v5_535))) + (= rn v5_541) (= - v2_544 + v5_544 (bvshl - (extract 63 0 v2_541) + (extract 63 0 v5_541) (extract 63 0 @@ -107,7 +257,7 @@ (if (bvslt (bvsrem - v2_537 + v5_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000000)) (if @@ -116,20 +266,23 @@ (concat #x0000000000000000 #x0000000000000000)) (bvsub (bvsrem - v2_537 + v5_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000040)) (bvadd (bvsrem - v2_537 + v5_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000040))) (bvsrem - v2_537 + v5_537 (concat #x0000000000000000 #x0000000000000040)))))))) - (= rd v2_544)))) + (= rd v5_544)))) (require (or + (and (= alu_op (ALUOp.Lsr)) (= size (OperandSize.Size32))) (and (= alu_op (ALUOp.Lsr)) (= size (OperandSize.Size64))) + (and (= alu_op (ALUOp.Asr)) (= size (OperandSize.Size32))) (and (= alu_op (ALUOp.Asr)) (= size (OperandSize.Size64))) + (and (= alu_op (ALUOp.Lsl)) (= size (OperandSize.Size32))) (and (= alu_op (ALUOp.Lsl)) (= size (OperandSize.Size64)))))) diff --git a/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs b/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs index 90d7e9e2e1e1..0dd6502a1e4e 100644 --- a/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs +++ b/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs @@ -19,6 +19,7 @@ use isla_lib::simplify::{self, WriteOpts}; use isla_lib::smt::smtlib; use isla_lib::smt::{self, Checkpoint, Event, Solver, Sym}; use isla_lib::zencode; +use itertools::Itertools; use sha2::{Digest, Sha256}; use std::collections::{HashMap, HashSet}; use std::io::prelude::*; @@ -102,6 +103,12 @@ fn define() -> Vec { //ALUOp::SbcS, ]; + // OperandSize + let sizes = vec![ + OperandSize::Size32, + OperandSize::Size64, + ]; + // AluRRR let alu_rrr = SpecConfig { // Spec signature. @@ -113,10 +120,11 @@ fn define() -> Vec { cases: alu_ops .iter() .copied() - .map(|alu_op| InstConfig { + .cartesian_product(sizes) + .map(|(alu_op, size)| InstConfig { inst: Inst::AluRRR { alu_op, - size: OperandSize::Size64, + size, rd: writable_xreg(4), rn: xreg(5), rm: xreg(6), @@ -130,7 +138,7 @@ fn define() -> Vec { ), spec_eq( spec_var("size".to_string()), - spec_enum("OperandSize".to_string(), "Size64".to_string()), + spec_enum("OperandSize".to_string(), format!("{size:?}")), ), ], diff --git a/cranelift/isle/veri/veri_engine/src/lib.rs b/cranelift/isle/veri/veri_engine/src/lib.rs index dfc315b9ee36..1ce4a4863c4c 100644 --- a/cranelift/isle/veri/veri_engine/src/lib.rs +++ b/cranelift/isle/veri/veri_engine/src/lib.rs @@ -16,7 +16,7 @@ pub mod verify; pub const REG_WIDTH: usize = 64; // Use a distinct with as the maximum width any value should have within type inference -pub const MAX_WIDTH: usize = 4*REG_WIDTH; +pub const MAX_WIDTH: usize = 2 * REG_WIDTH; pub const FLAGS_WIDTH: usize = 4; From 53743239068ef254ab76b14e89279ee1766eafb6 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Mon, 19 Feb 2024 00:20:45 -0500 Subject: [PATCH 71/73] extend sail spec to all bitwidths --- cranelift/codegen/src/isa/aarch64/inst.isle | 20 ++- .../codegen/src/isa/aarch64/inst_specs.isle | 146 +++++++++++------- .../isle/veri/veri_engine/src/bin/isaspec.rs | 7 +- 3 files changed, 102 insertions(+), 71 deletions(-) diff --git a/cranelift/codegen/src/isa/aarch64/inst.isle b/cranelift/codegen/src/isa/aarch64/inst.isle index 7d44bace3e79..8d376e386141 100644 --- a/cranelift/codegen/src/isa/aarch64/inst.isle +++ b/cranelift/codegen/src/isa/aarch64/inst.isle @@ -2018,6 +2018,10 @@ (spec (alu_rrr op t a b) (provide (= result (switch op + ((ALUOp.Add) + (if (<= t 32) + (zero_ext 64 (bvadd (extract 31 0 a) (extract 31 0 b))) + (bvadd a b))) ((ALUOp.Lsr) (if (<= t 32) (zero_ext 64 (bvlshr (extract 31 0 a) (bvand (bvsub (int2bv 32 32) #x00000001) (extract 31 0 b)))) @@ -2031,9 +2035,9 @@ (zero_ext 64 (bvshl (extract 31 0 a) (bvand (bvsub (int2bv 32 32) #x00000001) (extract 31 0 b)))) (bvshl a (bvand (bvsub (int2bv 64 64) #x0000000000000001) b))))))) (require - (or (= op (ALUOp.Lsr)) (= op (ALUOp.Asr)) (= op (ALUOp.Lsl))) - ;(or (= t 8) (= t 16) (= t 32) (= t 64))) - (or (= t 32) (= t 64))) + (or (= op (ALUOp.Add)) (= op (ALUOp.Lsr)) (= op (ALUOp.Asr)) (= op (ALUOp.Lsl))) + (or (= t 8) (= t 16) (= t 32) (= t 64))) + ;(or (= t 32) (= t 64))) ) (decl alu_rrr (ALUOp Type Reg Reg) Reg) (instantiate alu_rrr @@ -2638,10 +2642,14 @@ (provide (= result (if (<= ty 32) - (conv_to 64 (bvadd (extract 31 0 a) (extract 31 0 b))) - (bvadd a b))))) + (zero_ext 64 (bvadd (extract 31 0 a) (extract 31 0 b))) + (bvadd a b)))) + (require (or (= ty 8) (= ty 16) (= ty 32) (= ty 64)))) (decl add (Type Reg Reg) Reg) -(rule (add ty x y) (alu_rrr (ALUOp.Add) ty x y)) +(instantiate add + ((args Int (bv 64) (bv 64)) (ret (bv 64)) (canon (bv 64))) +) +(rule add_alu_rrr (add ty x y) (alu_rrr (ALUOp.Add) ty x y)) (spec (add_imm ty a b) (provide diff --git a/cranelift/codegen/src/isa/aarch64/inst_specs.isle b/cranelift/codegen/src/isa/aarch64/inst_specs.isle index 69dffeb0fb4f..de20fb0e0c26 100644 --- a/cranelift/codegen/src/isa/aarch64/inst_specs.isle +++ b/cranelift/codegen/src/isa/aarch64/inst_specs.isle @@ -2,18 +2,42 @@ (MInst.AluRRR alu_op size rd rn rm) (provide (= result #b1) + (=> + (and (= alu_op (ALUOp.Add)) (= size (OperandSize.Size32))) + (and + (= rn v0_536) + (= rm v0_538) + (= + v0_581 + (zero_ext + 64 + (bvadd + (extract 31 0 (zero_ext 128 (extract 31 0 v0_536))) + (extract 31 0 (zero_ext 128 (extract 31 0 v0_538)))))) + (= rd v0_581))) + (=> + (and (= alu_op (ALUOp.Add)) (= size (OperandSize.Size64))) + (and + (= rn v1_536) + (= rm v1_538) + (= + v1_581 + (bvadd + (extract 63 0 (zero_ext 128 (extract 63 0 v1_536))) + (extract 63 0 (zero_ext 128 (extract 63 0 v1_538))))) + (= rd v1_581))) (=> (and (= alu_op (ALUOp.Lsr)) (= size (OperandSize.Size32))) (and - (= rm v0_535) - (= v0_537 (zero_ext 128 (extract 31 0 v0_535))) - (= rn v0_541) + (= rm v2_535) + (= v2_537 (zero_ext 128 (extract 31 0 v2_535))) + (= rn v2_541) (= - v0_544 + v2_544 (zero_ext 64 (bvlshr - (extract 31 0 v0_541) + (extract 31 0 v2_541) (extract 31 0 @@ -25,7 +49,7 @@ (if (bvslt (bvsrem - v0_537 + v2_537 (concat #x0000000000000000 #x0000000000000020)) (concat #x0000000000000000 #x0000000000000000)) (if @@ -34,34 +58,34 @@ (concat #x0000000000000000 #x0000000000000000)) (bvsub (bvsrem - v0_537 + v2_537 (concat #x0000000000000000 #x0000000000000020)) (concat #x0000000000000000 #x0000000000000020)) (bvadd (bvsrem - v0_537 + v2_537 (concat #x0000000000000000 #x0000000000000020)) (concat #x0000000000000000 #x0000000000000020))) (bvsrem - v0_537 + v2_537 (concat #x0000000000000000 #x0000000000000020))))))))) - (= rd v0_544))) + (= rd v2_544))) (=> (and (= alu_op (ALUOp.Lsr)) (= size (OperandSize.Size64))) (and - (= rm v1_535) - (= v1_537 (zero_ext 128 (extract 63 0 v1_535))) - (= rn v1_541) + (= rm v3_535) + (= v3_537 (zero_ext 128 (extract 63 0 v3_535))) + (= rn v3_541) (= - v1_544 + v3_544 (bvlshr - (extract 63 0 v1_541) + (extract 63 0 v3_541) (extract 63 0 @@ -73,7 +97,7 @@ (if (bvslt (bvsrem - v1_537 + v3_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000000)) (if @@ -82,30 +106,30 @@ (concat #x0000000000000000 #x0000000000000000)) (bvsub (bvsrem - v1_537 + v3_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000040)) (bvadd (bvsrem - v1_537 + v3_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000040))) (bvsrem - v1_537 + v3_537 (concat #x0000000000000000 #x0000000000000040)))))))) - (= rd v1_544))) + (= rd v3_544))) (=> (and (= alu_op (ALUOp.Asr)) (= size (OperandSize.Size32))) (and - (= rm v2_535) - (= v2_537 (zero_ext 128 (extract 31 0 v2_535))) - (= rn v2_541) + (= rm v4_535) + (= v4_537 (zero_ext 128 (extract 31 0 v4_535))) + (= rn v4_541) (= - v2_544 + v4_544 (zero_ext 64 (bvashr - (extract 31 0 v2_541) + (extract 31 0 v4_541) (extract 31 0 @@ -117,7 +141,7 @@ (if (bvslt (bvsrem - v2_537 + v4_537 (concat #x0000000000000000 #x0000000000000020)) (concat #x0000000000000000 #x0000000000000000)) (if @@ -126,34 +150,34 @@ (concat #x0000000000000000 #x0000000000000000)) (bvsub (bvsrem - v2_537 + v4_537 (concat #x0000000000000000 #x0000000000000020)) (concat #x0000000000000000 #x0000000000000020)) (bvadd (bvsrem - v2_537 + v4_537 (concat #x0000000000000000 #x0000000000000020)) (concat #x0000000000000000 #x0000000000000020))) (bvsrem - v2_537 + v4_537 (concat #x0000000000000000 #x0000000000000020))))))))) - (= rd v2_544))) + (= rd v4_544))) (=> (and (= alu_op (ALUOp.Asr)) (= size (OperandSize.Size64))) (and - (= rm v3_535) - (= v3_537 (zero_ext 128 (extract 63 0 v3_535))) - (= rn v3_541) + (= rm v5_535) + (= v5_537 (zero_ext 128 (extract 63 0 v5_535))) + (= rn v5_541) (= - v3_544 + v5_544 (bvashr - (extract 63 0 v3_541) + (extract 63 0 v5_541) (extract 63 0 @@ -165,7 +189,7 @@ (if (bvslt (bvsrem - v3_537 + v5_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000000)) (if @@ -174,30 +198,30 @@ (concat #x0000000000000000 #x0000000000000000)) (bvsub (bvsrem - v3_537 + v5_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000040)) (bvadd (bvsrem - v3_537 + v5_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000040))) (bvsrem - v3_537 + v5_537 (concat #x0000000000000000 #x0000000000000040)))))))) - (= rd v3_544))) + (= rd v5_544))) (=> (and (= alu_op (ALUOp.Lsl)) (= size (OperandSize.Size32))) (and - (= rm v4_535) - (= v4_537 (zero_ext 128 (extract 31 0 v4_535))) - (= rn v4_541) + (= rm v6_535) + (= v6_537 (zero_ext 128 (extract 31 0 v6_535))) + (= rn v6_541) (= - v4_544 + v6_544 (zero_ext 64 (bvshl - (extract 31 0 v4_541) + (extract 31 0 v6_541) (extract 31 0 @@ -209,7 +233,7 @@ (if (bvslt (bvsrem - v4_537 + v6_537 (concat #x0000000000000000 #x0000000000000020)) (concat #x0000000000000000 #x0000000000000000)) (if @@ -218,34 +242,34 @@ (concat #x0000000000000000 #x0000000000000000)) (bvsub (bvsrem - v4_537 + v6_537 (concat #x0000000000000000 #x0000000000000020)) (concat #x0000000000000000 #x0000000000000020)) (bvadd (bvsrem - v4_537 + v6_537 (concat #x0000000000000000 #x0000000000000020)) (concat #x0000000000000000 #x0000000000000020))) (bvsrem - v4_537 + v6_537 (concat #x0000000000000000 #x0000000000000020))))))))) - (= rd v4_544))) + (= rd v6_544))) (=> (and (= alu_op (ALUOp.Lsl)) (= size (OperandSize.Size64))) (and - (= rm v5_535) - (= v5_537 (zero_ext 128 (extract 63 0 v5_535))) - (= rn v5_541) + (= rm v7_535) + (= v7_537 (zero_ext 128 (extract 63 0 v7_535))) + (= rn v7_541) (= - v5_544 + v7_544 (bvshl - (extract 63 0 v5_541) + (extract 63 0 v7_541) (extract 63 0 @@ -257,7 +281,7 @@ (if (bvslt (bvsrem - v5_537 + v7_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000000)) (if @@ -266,20 +290,22 @@ (concat #x0000000000000000 #x0000000000000000)) (bvsub (bvsrem - v5_537 + v7_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000040)) (bvadd (bvsrem - v5_537 + v7_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000040))) (bvsrem - v5_537 + v7_537 (concat #x0000000000000000 #x0000000000000040)))))))) - (= rd v5_544)))) + (= rd v7_544)))) (require (or + (and (= alu_op (ALUOp.Add)) (= size (OperandSize.Size32))) + (and (= alu_op (ALUOp.Add)) (= size (OperandSize.Size64))) (and (= alu_op (ALUOp.Lsr)) (= size (OperandSize.Size32))) (and (= alu_op (ALUOp.Lsr)) (= size (OperandSize.Size64))) (and (= alu_op (ALUOp.Asr)) (= size (OperandSize.Size32))) diff --git a/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs b/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs index 0dd6502a1e4e..5dadf12a6340 100644 --- a/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs +++ b/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs @@ -78,7 +78,7 @@ fn main() -> anyhow::Result<()> { fn define() -> Vec { // ALUOp let alu_ops = vec![ - //ALUOp::Add, + ALUOp::Add, //ALUOp::Sub, //ALUOp::Orr, //ALUOp::OrrNot, @@ -104,10 +104,7 @@ fn define() -> Vec { ]; // OperandSize - let sizes = vec![ - OperandSize::Size32, - OperandSize::Size64, - ]; + let sizes = vec![OperandSize::Size32, OperandSize::Size64]; // AluRRR let alu_rrr = SpecConfig { From 7bf9cc40670147cbd00118404a3f2609abf70e83 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Mon, 19 Feb 2024 12:26:24 -0500 Subject: [PATCH 72/73] add more aluops --- .../codegen/src/isa/aarch64/inst_specs.isle | 256 ++++++++++++++---- .../isle/veri/veri_engine/src/bin/isaspec.rs | 14 +- 2 files changed, 203 insertions(+), 67 deletions(-) diff --git a/cranelift/codegen/src/isa/aarch64/inst_specs.isle b/cranelift/codegen/src/isa/aarch64/inst_specs.isle index de20fb0e0c26..6cb44fa423d8 100644 --- a/cranelift/codegen/src/isa/aarch64/inst_specs.isle +++ b/cranelift/codegen/src/isa/aarch64/inst_specs.isle @@ -26,18 +26,140 @@ (extract 63 0 (zero_ext 128 (extract 63 0 v1_536))) (extract 63 0 (zero_ext 128 (extract 63 0 v1_538))))) (= rd v1_581))) + (=> + (and (= alu_op (ALUOp.Sub)) (= size (OperandSize.Size32))) + (and + (= rn v2_536) + (= rm v2_538) + (= + v2_584 + (zero_ext + 64 + (bvadd + (extract + 31 + 0 + (bvadd + (zero_ext 128 (extract 31 0 v2_536)) + (zero_ext 128 (bvnot (extract 31 0 v2_538))))) + #x00000001))) + (= rd v2_584))) + (=> + (and (= alu_op (ALUOp.Sub)) (= size (OperandSize.Size64))) + (and + (= rn v3_536) + (= rm v3_538) + (= + v3_584 + (bvadd + (extract + 63 + 0 + (bvadd + (zero_ext 128 (extract 63 0 v3_536)) + (zero_ext 128 (bvnot (extract 63 0 v3_538))))) + #x0000000000000001)) + (= rd v3_584))) + (=> + (and (= alu_op (ALUOp.Orr)) (= size (OperandSize.Size32))) + (and + (= rn v4_544) + (= rm v4_546) + (= v4_550 (zero_ext 64 (bvor (extract 31 0 v4_544) (extract 31 0 v4_546)))) + (= rd v4_550))) + (=> + (and (= alu_op (ALUOp.Orr)) (= size (OperandSize.Size64))) + (and + (= rn v5_544) + (= rm v5_546) + (= v5_550 (bvor (extract 63 0 v5_544) (extract 63 0 v5_546))) + (= rd v5_550))) + (=> + (and (= alu_op (ALUOp.OrrNot)) (= size (OperandSize.Size32))) + (and + (= rn v6_544) + (= rm v6_546) + (= v6_551 (zero_ext 64 (bvor (extract 31 0 v6_544) (bvnot (extract 31 0 v6_546))))) + (= rd v6_551))) + (=> + (and (= alu_op (ALUOp.OrrNot)) (= size (OperandSize.Size64))) + (and + (= rn v7_544) + (= rm v7_546) + (= v7_551 (bvor (extract 63 0 v7_544) (bvnot (extract 63 0 v7_546)))) + (= rd v7_551))) + (=> + (and (= alu_op (ALUOp.And)) (= size (OperandSize.Size32))) + (and + (= rn v8_544) + (= rm v8_546) + (= v8_550 (zero_ext 64 (bvand (extract 31 0 v8_544) (extract 31 0 v8_546)))) + (= rd v8_550))) + (=> + (and (= alu_op (ALUOp.And)) (= size (OperandSize.Size64))) + (and + (= rn v9_544) + (= rm v9_546) + (= v9_550 (bvand (extract 63 0 v9_544) (extract 63 0 v9_546))) + (= rd v9_550))) + (=> + (and (= alu_op (ALUOp.AndNot)) (= size (OperandSize.Size32))) + (and + (= rn v10_544) + (= rm v10_546) + (= + v10_551 + (zero_ext 64 (bvand (extract 31 0 v10_544) (bvnot (extract 31 0 v10_546))))) + (= rd v10_551))) + (=> + (and (= alu_op (ALUOp.AndNot)) (= size (OperandSize.Size64))) + (and + (= rn v11_544) + (= rm v11_546) + (= v11_551 (bvand (extract 63 0 v11_544) (bvnot (extract 63 0 v11_546)))) + (= rd v11_551))) + (=> + (and (= alu_op (ALUOp.Eor)) (= size (OperandSize.Size32))) + (and + (= rn v12_544) + (= rm v12_546) + (= v12_550 (zero_ext 64 (bvxor (extract 31 0 v12_544) (extract 31 0 v12_546)))) + (= rd v12_550))) + (=> + (and (= alu_op (ALUOp.Eor)) (= size (OperandSize.Size64))) + (and + (= rn v13_544) + (= rm v13_546) + (= v13_550 (bvxor (extract 63 0 v13_544) (extract 63 0 v13_546))) + (= rd v13_550))) + (=> + (and (= alu_op (ALUOp.EorNot)) (= size (OperandSize.Size32))) + (and + (= rn v14_544) + (= rm v14_546) + (= + v14_551 + (zero_ext 64 (bvxor (extract 31 0 v14_544) (bvnot (extract 31 0 v14_546))))) + (= rd v14_551))) + (=> + (and (= alu_op (ALUOp.EorNot)) (= size (OperandSize.Size64))) + (and + (= rn v15_544) + (= rm v15_546) + (= v15_551 (bvxor (extract 63 0 v15_544) (bvnot (extract 63 0 v15_546)))) + (= rd v15_551))) (=> (and (= alu_op (ALUOp.Lsr)) (= size (OperandSize.Size32))) (and - (= rm v2_535) - (= v2_537 (zero_ext 128 (extract 31 0 v2_535))) - (= rn v2_541) + (= rm v16_535) + (= v16_537 (zero_ext 128 (extract 31 0 v16_535))) + (= rn v16_541) (= - v2_544 + v16_544 (zero_ext 64 (bvlshr - (extract 31 0 v2_541) + (extract 31 0 v16_541) (extract 31 0 @@ -49,7 +171,7 @@ (if (bvslt (bvsrem - v2_537 + v16_537 (concat #x0000000000000000 #x0000000000000020)) (concat #x0000000000000000 #x0000000000000000)) (if @@ -58,34 +180,34 @@ (concat #x0000000000000000 #x0000000000000000)) (bvsub (bvsrem - v2_537 + v16_537 (concat #x0000000000000000 #x0000000000000020)) (concat #x0000000000000000 #x0000000000000020)) (bvadd (bvsrem - v2_537 + v16_537 (concat #x0000000000000000 #x0000000000000020)) (concat #x0000000000000000 #x0000000000000020))) (bvsrem - v2_537 + v16_537 (concat #x0000000000000000 #x0000000000000020))))))))) - (= rd v2_544))) + (= rd v16_544))) (=> (and (= alu_op (ALUOp.Lsr)) (= size (OperandSize.Size64))) (and - (= rm v3_535) - (= v3_537 (zero_ext 128 (extract 63 0 v3_535))) - (= rn v3_541) + (= rm v17_535) + (= v17_537 (zero_ext 128 (extract 63 0 v17_535))) + (= rn v17_541) (= - v3_544 + v17_544 (bvlshr - (extract 63 0 v3_541) + (extract 63 0 v17_541) (extract 63 0 @@ -97,7 +219,7 @@ (if (bvslt (bvsrem - v3_537 + v17_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000000)) (if @@ -106,30 +228,30 @@ (concat #x0000000000000000 #x0000000000000000)) (bvsub (bvsrem - v3_537 + v17_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000040)) (bvadd (bvsrem - v3_537 + v17_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000040))) (bvsrem - v3_537 + v17_537 (concat #x0000000000000000 #x0000000000000040)))))))) - (= rd v3_544))) + (= rd v17_544))) (=> (and (= alu_op (ALUOp.Asr)) (= size (OperandSize.Size32))) (and - (= rm v4_535) - (= v4_537 (zero_ext 128 (extract 31 0 v4_535))) - (= rn v4_541) + (= rm v18_535) + (= v18_537 (zero_ext 128 (extract 31 0 v18_535))) + (= rn v18_541) (= - v4_544 + v18_544 (zero_ext 64 (bvashr - (extract 31 0 v4_541) + (extract 31 0 v18_541) (extract 31 0 @@ -141,7 +263,7 @@ (if (bvslt (bvsrem - v4_537 + v18_537 (concat #x0000000000000000 #x0000000000000020)) (concat #x0000000000000000 #x0000000000000000)) (if @@ -150,34 +272,34 @@ (concat #x0000000000000000 #x0000000000000000)) (bvsub (bvsrem - v4_537 + v18_537 (concat #x0000000000000000 #x0000000000000020)) (concat #x0000000000000000 #x0000000000000020)) (bvadd (bvsrem - v4_537 + v18_537 (concat #x0000000000000000 #x0000000000000020)) (concat #x0000000000000000 #x0000000000000020))) (bvsrem - v4_537 + v18_537 (concat #x0000000000000000 #x0000000000000020))))))))) - (= rd v4_544))) + (= rd v18_544))) (=> (and (= alu_op (ALUOp.Asr)) (= size (OperandSize.Size64))) (and - (= rm v5_535) - (= v5_537 (zero_ext 128 (extract 63 0 v5_535))) - (= rn v5_541) + (= rm v19_535) + (= v19_537 (zero_ext 128 (extract 63 0 v19_535))) + (= rn v19_541) (= - v5_544 + v19_544 (bvashr - (extract 63 0 v5_541) + (extract 63 0 v19_541) (extract 63 0 @@ -189,7 +311,7 @@ (if (bvslt (bvsrem - v5_537 + v19_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000000)) (if @@ -198,30 +320,30 @@ (concat #x0000000000000000 #x0000000000000000)) (bvsub (bvsrem - v5_537 + v19_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000040)) (bvadd (bvsrem - v5_537 + v19_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000040))) (bvsrem - v5_537 + v19_537 (concat #x0000000000000000 #x0000000000000040)))))))) - (= rd v5_544))) + (= rd v19_544))) (=> (and (= alu_op (ALUOp.Lsl)) (= size (OperandSize.Size32))) (and - (= rm v6_535) - (= v6_537 (zero_ext 128 (extract 31 0 v6_535))) - (= rn v6_541) + (= rm v20_535) + (= v20_537 (zero_ext 128 (extract 31 0 v20_535))) + (= rn v20_541) (= - v6_544 + v20_544 (zero_ext 64 (bvshl - (extract 31 0 v6_541) + (extract 31 0 v20_541) (extract 31 0 @@ -233,7 +355,7 @@ (if (bvslt (bvsrem - v6_537 + v20_537 (concat #x0000000000000000 #x0000000000000020)) (concat #x0000000000000000 #x0000000000000000)) (if @@ -242,34 +364,34 @@ (concat #x0000000000000000 #x0000000000000000)) (bvsub (bvsrem - v6_537 + v20_537 (concat #x0000000000000000 #x0000000000000020)) (concat #x0000000000000000 #x0000000000000020)) (bvadd (bvsrem - v6_537 + v20_537 (concat #x0000000000000000 #x0000000000000020)) (concat #x0000000000000000 #x0000000000000020))) (bvsrem - v6_537 + v20_537 (concat #x0000000000000000 #x0000000000000020))))))))) - (= rd v6_544))) + (= rd v20_544))) (=> (and (= alu_op (ALUOp.Lsl)) (= size (OperandSize.Size64))) (and - (= rm v7_535) - (= v7_537 (zero_ext 128 (extract 63 0 v7_535))) - (= rn v7_541) + (= rm v21_535) + (= v21_537 (zero_ext 128 (extract 63 0 v21_535))) + (= rn v21_541) (= - v7_544 + v21_544 (bvshl - (extract 63 0 v7_541) + (extract 63 0 v21_541) (extract 63 0 @@ -281,7 +403,7 @@ (if (bvslt (bvsrem - v7_537 + v21_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000000)) (if @@ -290,22 +412,36 @@ (concat #x0000000000000000 #x0000000000000000)) (bvsub (bvsrem - v7_537 + v21_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000040)) (bvadd (bvsrem - v7_537 + v21_537 (concat #x0000000000000000 #x0000000000000040)) (concat #x0000000000000000 #x0000000000000040))) (bvsrem - v7_537 + v21_537 (concat #x0000000000000000 #x0000000000000040)))))))) - (= rd v7_544)))) + (= rd v21_544)))) (require (or (and (= alu_op (ALUOp.Add)) (= size (OperandSize.Size32))) (and (= alu_op (ALUOp.Add)) (= size (OperandSize.Size64))) + (and (= alu_op (ALUOp.Sub)) (= size (OperandSize.Size32))) + (and (= alu_op (ALUOp.Sub)) (= size (OperandSize.Size64))) + (and (= alu_op (ALUOp.Orr)) (= size (OperandSize.Size32))) + (and (= alu_op (ALUOp.Orr)) (= size (OperandSize.Size64))) + (and (= alu_op (ALUOp.OrrNot)) (= size (OperandSize.Size32))) + (and (= alu_op (ALUOp.OrrNot)) (= size (OperandSize.Size64))) + (and (= alu_op (ALUOp.And)) (= size (OperandSize.Size32))) + (and (= alu_op (ALUOp.And)) (= size (OperandSize.Size64))) + (and (= alu_op (ALUOp.AndNot)) (= size (OperandSize.Size32))) + (and (= alu_op (ALUOp.AndNot)) (= size (OperandSize.Size64))) + (and (= alu_op (ALUOp.Eor)) (= size (OperandSize.Size32))) + (and (= alu_op (ALUOp.Eor)) (= size (OperandSize.Size64))) + (and (= alu_op (ALUOp.EorNot)) (= size (OperandSize.Size32))) + (and (= alu_op (ALUOp.EorNot)) (= size (OperandSize.Size64))) (and (= alu_op (ALUOp.Lsr)) (= size (OperandSize.Size32))) (and (= alu_op (ALUOp.Lsr)) (= size (OperandSize.Size64))) (and (= alu_op (ALUOp.Asr)) (= size (OperandSize.Size32))) diff --git a/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs b/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs index 5dadf12a6340..c80b570164fb 100644 --- a/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs +++ b/cranelift/isle/veri/veri_engine/src/bin/isaspec.rs @@ -79,13 +79,13 @@ fn define() -> Vec { // ALUOp let alu_ops = vec![ ALUOp::Add, - //ALUOp::Sub, - //ALUOp::Orr, - //ALUOp::OrrNot, - //ALUOp::And, - //ALUOp::AndNot, - //ALUOp::Eor, - //ALUOp::EorNot, + ALUOp::Sub, + ALUOp::Orr, + ALUOp::OrrNot, + ALUOp::And, + ALUOp::AndNot, + ALUOp::Eor, + ALUOp::EorNot, ALUOp::Lsr, ALUOp::Asr, ALUOp::Lsl, From 9eba5f6c5173324984ce2785c17c8d0acc4369e4 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Mon, 19 Feb 2024 12:33:05 -0500 Subject: [PATCH 73/73] define isla dependency with git --- Cargo.lock | 7 +++++++ cranelift/isle/veri/veri_engine/Cargo.toml | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7ad72a3b0f5f..86134ce48123 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1847,6 +1847,7 @@ dependencies = [ [[package]] name = "isla" version = "0.2.0" +source = "git+https://github.com/rems-project/isla.git?rev=2a4bd429b56634db52d59707b83090a535b5c4bc#2a4bd429b56634db52d59707b83090a535b5c4bc" dependencies = [ "bincode", "crossbeam", @@ -1866,6 +1867,7 @@ dependencies = [ [[package]] name = "isla-axiomatic" version = "0.2.0" +source = "git+https://github.com/rems-project/isla.git?rev=2a4bd429b56634db52d59707b83090a535b5c4bc#2a4bd429b56634db52d59707b83090a535b5c4bc" dependencies = [ "crossbeam", "goblin", @@ -1884,6 +1886,7 @@ dependencies = [ [[package]] name = "isla-cat" version = "0.2.0" +source = "git+https://github.com/rems-project/isla.git?rev=2a4bd429b56634db52d59707b83090a535b5c4bc#2a4bd429b56634db52d59707b83090a535b5c4bc" dependencies = [ "lalrpop", "lalrpop-util", @@ -1894,6 +1897,7 @@ dependencies = [ [[package]] name = "isla-elf" version = "0.2.0" +source = "git+https://github.com/rems-project/isla.git?rev=2a4bd429b56634db52d59707b83090a535b5c4bc#2a4bd429b56634db52d59707b83090a535b5c4bc" dependencies = [ "gimli 0.26.2", "goblin", @@ -1904,6 +1908,7 @@ dependencies = [ [[package]] name = "isla-lib" version = "0.2.0" +source = "git+https://github.com/rems-project/isla.git?rev=2a4bd429b56634db52d59707b83090a535b5c4bc#2a4bd429b56634db52d59707b83090a535b5c4bc" dependencies = [ "ahash 0.7.7", "bincode", @@ -1925,6 +1930,7 @@ dependencies = [ [[package]] name = "isla-mml" version = "0.2.0" +source = "git+https://github.com/rems-project/isla.git?rev=2a4bd429b56634db52d59707b83090a535b5c4bc#2a4bd429b56634db52d59707b83090a535b5c4bc" dependencies = [ "id-arena", "isla-lib", @@ -1937,6 +1943,7 @@ dependencies = [ [[package]] name = "isla-sexp" version = "0.2.0" +source = "git+https://github.com/rems-project/isla.git?rev=2a4bd429b56634db52d59707b83090a535b5c4bc#2a4bd429b56634db52d59707b83090a535b5c4bc" dependencies = [ "isla-mml", "proc-macro2", diff --git a/cranelift/isle/veri/veri_engine/Cargo.toml b/cranelift/isle/veri/veri_engine/Cargo.toml index 1b6546dd9f83..18debe0bfc58 100644 --- a/cranelift/isle/veri/veri_engine/Cargo.toml +++ b/cranelift/isle/veri/veri_engine/Cargo.toml @@ -30,8 +30,8 @@ cranelift-isle = { path = "../../isle" } cranelift-codegen = { path = "../../../codegen" } cranelift-reader = { path = "../../../reader" } cranelift-codegen-meta = { path = "../../../codegen/meta" } -isla = { path = "../../../../../isla" } -isla-lib = { path = "../../../../../isla/isla-lib" } +isla = { git = "https://github.com/rems-project/isla.git", rev = "2a4bd429b56634db52d59707b83090a535b5c4bc" } +isla-lib = { git = "https://github.com/rems-project/isla.git", rev = "2a4bd429b56634db52d59707b83090a535b5c4bc" } anyhow = { workspace = true } veri_ir = { path = "../veri_ir" } easy-smt = { git = "https://github.com/elliottt/easy-smt.git" }