Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/isle/veri/veri_engine/tests/utils/mod.rs
1693 views
1
use cranelift_codegen_meta::{
2
generate_isle,
3
isle::{get_isle_compilations, shared_isle_lower_paths},
4
};
5
use cranelift_isle::compile::create_envs;
6
use std::env;
7
use std::path::PathBuf;
8
use strum::IntoEnumIterator;
9
use strum_macros::EnumIter;
10
use veri_engine_lib::annotations::parse_annotations;
11
use veri_engine_lib::type_inference::type_rules_with_term_and_types;
12
use veri_engine_lib::verify::verify_rules_for_term;
13
use veri_engine_lib::Config;
14
use veri_ir::{ConcreteTest, Counterexample, TermSignature, VerificationResult};
15
16
#[derive(Debug, EnumIter, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
17
#[repr(usize)]
18
pub enum Bitwidth {
19
I8 = 8,
20
I16 = 16,
21
I32 = 32,
22
I64 = 64,
23
}
24
25
pub enum TestResult {
26
Simple(Vec<(Bitwidth, VerificationResult)>),
27
Expect(fn(&TermSignature) -> VerificationResult),
28
}
29
30
type TestResultBuilder = dyn Fn(Bitwidth) -> (Bitwidth, VerificationResult);
31
32
use std::sync::Once;
33
34
static INIT: Once = Once::new();
35
36
pub fn get_isle_files(name: &str) -> Vec<std::path::PathBuf> {
37
let cur_dir = env::current_dir().expect("Can't access current working directory");
38
let gen_dir = cur_dir.join("test_output");
39
INIT.call_once(|| {
40
// Logger
41
env_logger::init();
42
// Test directory
43
if !gen_dir.is_dir() {
44
std::fs::create_dir(gen_dir.as_path()).unwrap();
45
}
46
// Generate ISLE files.
47
generate_isle(gen_dir.as_path()).expect("Can't generate ISLE");
48
});
49
50
let codegen_crate_dir = cur_dir.join("../../../codegen");
51
let inst_specs_isle = codegen_crate_dir.join("src").join("inst_specs.isle");
52
53
match name {
54
"shared_lower" => {
55
let mut shared = shared_isle_lower_paths(codegen_crate_dir.as_path());
56
shared.push(gen_dir.join("clif_lower.isle"));
57
shared
58
}
59
_ => {
60
// Lookup ISLE shared .
61
let compilations =
62
get_isle_compilations(codegen_crate_dir.as_path(), gen_dir.as_path());
63
64
// Return inputs from the matching compilation, if any.
65
let mut inputs = compilations.lookup(name).unwrap().inputs();
66
inputs.push(inst_specs_isle);
67
inputs
68
}
69
}
70
}
71
72
// Some examples of functions we might need
73
#[allow(dead_code)]
74
pub fn just_8_result() -> TestResult {
75
TestResult::Simple(vec![(Bitwidth::I8, VerificationResult::Success)])
76
}
77
78
#[allow(dead_code)]
79
pub fn just_16_result() -> TestResult {
80
TestResult::Simple(vec![(Bitwidth::I16, VerificationResult::Success)])
81
}
82
83
#[allow(dead_code)]
84
pub fn just_32_result() -> TestResult {
85
TestResult::Simple(vec![(Bitwidth::I32, VerificationResult::Success)])
86
}
87
88
#[allow(dead_code)]
89
pub fn just_64_result() -> TestResult {
90
TestResult::Simple(vec![(Bitwidth::I64, VerificationResult::Success)])
91
}
92
93
/// All bitwidths verify
94
#[allow(dead_code)]
95
pub fn all_success_result() -> Vec<(Bitwidth, VerificationResult)> {
96
custom_result(&|w| (w, VerificationResult::Success))
97
}
98
99
/// All bitwidths fail
100
#[allow(dead_code)]
101
pub fn all_failure_result() -> Vec<(Bitwidth, VerificationResult)> {
102
custom_result(&|w| (w, VerificationResult::Failure(Counterexample {})))
103
}
104
105
/// Specify a custom set expected result (helpful if you want to test all the bitwidths and expect
106
/// a range of different success, failure, and inapplicable outcomes)
107
pub fn custom_result(f: &TestResultBuilder) -> Vec<(Bitwidth, VerificationResult)> {
108
Bitwidth::iter().map(f).collect()
109
}
110
111
fn test_rules_with_term(inputs: Vec<PathBuf>, tr: TestResult, config: Config) {
112
let (typeenv, termenv, defs) = create_envs(inputs).unwrap();
113
let annotation_env = parse_annotations(&defs, &termenv, &typeenv);
114
115
let term_signatures = annotation_env
116
.get_term_signatures_by_name(&termenv, &typeenv)
117
.get(config.term.as_str())
118
.unwrap_or_else(|| panic!("Missing term type instantiation for {}", config.term))
119
.clone();
120
let instantiations = match tr {
121
TestResult::Simple(s) => {
122
let mut res = vec![];
123
for (width, result) in s {
124
let ty = match width {
125
Bitwidth::I8 => veri_ir::Type::BitVector(Some(8)),
126
Bitwidth::I16 => veri_ir::Type::BitVector(Some(16)),
127
Bitwidth::I32 => veri_ir::Type::BitVector(Some(32)),
128
Bitwidth::I64 => veri_ir::Type::BitVector(Some(64)),
129
};
130
// Find the type instantiations with this as the canonical type
131
let all_instantiations: Vec<&TermSignature> = term_signatures
132
.iter()
133
.filter(|sig| sig.canonical_type.unwrap() == ty)
134
.collect();
135
if all_instantiations.is_empty() {
136
panic!("Missing type instantiation for width {width:?}");
137
}
138
for i in all_instantiations {
139
res.push((i.clone(), result.clone()));
140
}
141
}
142
res
143
}
144
TestResult::Expect(expect) => term_signatures
145
.iter()
146
.map(|sig| (sig.clone(), expect(sig)))
147
.collect(),
148
};
149
150
for (type_instantiation, expected_result) in instantiations {
151
log::debug!("Expected result: {expected_result:?}");
152
let type_sols = type_rules_with_term_and_types(
153
&termenv,
154
&typeenv,
155
&annotation_env,
156
&config,
157
&type_instantiation,
158
&None,
159
);
160
let result = verify_rules_for_term(
161
&termenv,
162
&typeenv,
163
&type_sols,
164
type_instantiation,
165
&None,
166
&config,
167
);
168
assert_eq!(result, expected_result);
169
}
170
}
171
172
pub fn test_from_file_with_lhs_termname_simple(
173
file: &str,
174
termname: String,
175
tr: Vec<(Bitwidth, VerificationResult)>,
176
) {
177
test_from_file_with_lhs_termname(file, termname, TestResult::Simple(tr))
178
}
179
180
pub fn test_from_file_with_lhs_termname(file: &str, termname: String, tr: TestResult) {
181
println!("Verifying {termname} rules in file: {file}");
182
let mut inputs = get_isle_files("shared_lower");
183
inputs.push(PathBuf::from(file));
184
let config = Config {
185
term: termname,
186
distinct_check: true,
187
custom_verification_condition: None,
188
custom_assumptions: None,
189
names: None,
190
};
191
test_rules_with_term(inputs, tr, config);
192
}
193
194
pub fn test_aarch64_rule_with_lhs_termname_simple(
195
rulename: &str,
196
termname: &str,
197
tr: Vec<(Bitwidth, VerificationResult)>,
198
) {
199
test_aarch64_rule_with_lhs_termname(rulename, termname, TestResult::Simple(tr))
200
}
201
202
pub fn test_aarch64_rule_with_lhs_termname(rulename: &str, termname: &str, tr: TestResult) {
203
println!("Verifying rule `{rulename}` with termname {termname} ");
204
let inputs = get_isle_files("aarch64");
205
let config = Config {
206
term: termname.to_string(),
207
distinct_check: true,
208
custom_verification_condition: None,
209
custom_assumptions: None,
210
names: Some(vec![rulename.to_string()]),
211
};
212
test_rules_with_term(inputs, tr, config);
213
}
214
215
pub fn test_x64_rule_with_lhs_termname_simple(
216
rulename: &str,
217
termname: &str,
218
tr: Vec<(Bitwidth, VerificationResult)>,
219
) {
220
test_x64_rule_with_lhs_termname(rulename, termname, TestResult::Simple(tr))
221
}
222
223
pub fn test_x64_rule_with_lhs_termname(rulename: &str, termname: &str, tr: TestResult) {
224
println!("Verifying rule `{rulename}` with termname {termname} ");
225
let inputs = get_isle_files("x64");
226
let config = Config {
227
term: termname.to_string(),
228
distinct_check: true,
229
custom_verification_condition: None,
230
custom_assumptions: None,
231
names: Some(vec![rulename.to_string()]),
232
};
233
test_rules_with_term(inputs, tr, config);
234
}
235
236
pub fn test_from_file_with_config_simple(
237
file: &str,
238
config: Config,
239
tr: Vec<(Bitwidth, VerificationResult)>,
240
) {
241
test_from_file_with_config(file, config, TestResult::Simple(tr))
242
}
243
pub fn test_from_file_with_config(file: &str, config: Config, tr: TestResult) {
244
println!("Verifying {} rules in file: {}", config.term, file);
245
let mut inputs = get_isle_files("shared_lower");
246
inputs.push(PathBuf::from(file));
247
test_rules_with_term(inputs, tr, config);
248
}
249
250
pub fn test_aarch64_with_config_simple(config: Config, tr: Vec<(Bitwidth, VerificationResult)>) {
251
test_aarch64_with_config(config, TestResult::Simple(tr))
252
}
253
254
pub fn test_aarch64_with_config(config: Config, tr: TestResult) {
255
println!(
256
"Verifying rules {:?} with termname {}",
257
config.names, config.term
258
);
259
let inputs = get_isle_files("aarch64");
260
test_rules_with_term(inputs, tr, config);
261
}
262
263
pub fn test_concrete_aarch64_rule_with_lhs_termname(
264
rulename: &str,
265
termname: &str,
266
concrete: ConcreteTest,
267
) {
268
println!("Verifying concrete input rule `{rulename}` with termname {termname} ");
269
let inputs = get_isle_files("aarch64");
270
let (typeenv, termenv, defs) = create_envs(inputs).unwrap();
271
let annotation_env = parse_annotations(&defs, &termenv, &typeenv);
272
273
let config = Config {
274
term: termname.to_string(),
275
distinct_check: false,
276
custom_verification_condition: None,
277
custom_assumptions: None,
278
names: Some(vec![rulename.to_string()]),
279
};
280
281
// Get the types/widths for this particular term
282
let args = concrete.args.iter().map(|i| i.ty).collect();
283
let ret = concrete.output.ty;
284
let t = TermSignature {
285
args,
286
ret,
287
canonical_type: None,
288
};
289
290
let type_sols = type_rules_with_term_and_types(
291
&termenv,
292
&typeenv,
293
&annotation_env,
294
&config,
295
&t,
296
&Some(concrete.clone()),
297
);
298
let result = verify_rules_for_term(&termenv, &typeenv, &type_sols, t, &Some(concrete), &config);
299
assert_eq!(result, VerificationResult::Success);
300
}
301
302
pub fn test_concrete_input_from_file_with_lhs_termname(
303
file: &str,
304
termname: String,
305
concrete: ConcreteTest,
306
) {
307
println!("Verifying concrete input {termname} rule in file: {file}");
308
let mut inputs = get_isle_files("shared_lower");
309
inputs.push(PathBuf::from(file));
310
311
let (typeenv, termenv, defs) = create_envs(inputs).unwrap();
312
let annotation_env = parse_annotations(&defs, &termenv, &typeenv);
313
314
let config = Config {
315
term: termname.clone(),
316
distinct_check: false,
317
custom_verification_condition: None,
318
custom_assumptions: None,
319
names: None,
320
};
321
322
// Get the types/widths for this particular term
323
let args = concrete.args.iter().map(|i| i.ty).collect();
324
let ret = concrete.output.ty;
325
let t = TermSignature {
326
args,
327
ret,
328
canonical_type: None,
329
};
330
331
let type_sols = type_rules_with_term_and_types(
332
&termenv,
333
&typeenv,
334
&annotation_env,
335
&config,
336
&t,
337
&Some(concrete.clone()),
338
);
339
let result = verify_rules_for_term(&termenv, &typeenv, &type_sols, t, &Some(concrete), &config);
340
assert_eq!(result, VerificationResult::Success);
341
}
342
343