1pub mod cls;
2pub mod clz;
3pub mod popcnt;
4pub mod rev;
5pub mod subs;
6
7#[cfg(test)]
8mod tests {
9 use super::*;
10 use crate::solver::SolverCtx;
11 use easy_smt::{Response, SExpr};
12 use std::collections::HashMap;
13 use veri_ir::TypeContext;
14
15 fn get_ctx() -> SolverCtx {
16 let smt = easy_smt::ContextBuilder::new()
17 .replay_file(Some(std::fs::File::create("encoding_tests.smt2").unwrap()))
18 .solver("z3", ["-smt2", "-in"])
19 .build()
20 .unwrap();
21 SolverCtx {
22 smt,
23 find_widths: false,
24 tyctx: TypeContext {
25 tyvars: HashMap::new(),
26 tymap: HashMap::new(),
27 tyvals: HashMap::new(),
28 bv_unknown_width_sets: HashMap::new(),
29 },
30 bitwidth: 64,
31 var_map: HashMap::new(),
32 width_vars: HashMap::new(),
33 width_assumptions: vec![],
34 additional_decls: vec![],
35 additional_assumptions: vec![],
36 additional_assertions: vec![],
37 fresh_bits_idx: 0,
38 lhs_load_args: None,
39 rhs_load_args: None,
40 lhs_store_args: None,
41 rhs_store_args: None,
42 lhs_flag: true,
43 load_return: None,
44 }
45 }
46
47 fn check_unary_encoding_with_solver(encoding: &str, input: &str, output: &str, width: usize) {
52 let mut ctx = get_ctx();
53
54 let ty = ctx.smt.bit_vec_sort(ctx.smt.numeral(width));
56 let input_var = ctx.declare("input".to_string(), ty);
57
58 ctx.additional_assumptions
60 .push(ctx.smt.eq(input_var, ctx.smt.atom(input)));
61
62 let output_from_call = match (encoding, width) {
64 ("rev", 8) => rev::rev8(&mut ctx, input_var, 0),
65 ("rev", 16) => rev::rev16(&mut ctx, input_var, 0),
66 ("rev", 32) => rev::rev32(&mut ctx, input_var, 0),
67 ("rev", 64) => rev::rev64(&mut ctx, input_var, 0),
68
69 ("clz", 8) => clz::clz8(&mut ctx, input_var, 0),
70 ("clz", 16) => clz::clz16(&mut ctx, input_var, 0),
71 ("clz", 32) => clz::clz32(&mut ctx, input_var, 0),
72 ("clz", 64) => clz::clz64(&mut ctx, input_var, 0),
73
74 ("cls", 8) => cls::cls8(&mut ctx, input_var, 0),
75 ("cls", 16) => cls::cls16(&mut ctx, input_var, 0),
76 ("cls", 32) => cls::cls32(&mut ctx, input_var, 0),
77 ("cls", 64) => cls::cls64(&mut ctx, input_var, 0),
78
79 ("popcnt", ty) => popcnt::popcnt(&mut ctx, ty, input_var, 0),
80 _ => unreachable!(),
81 };
82 check_encoding_with_solver(ctx, output_from_call, output, width)
83 }
84
85 fn check_encoding_with_solver(mut ctx: SolverCtx, call: SExpr, output: &str, width: usize) {
86 let output_care_bits = ctx.smt.extract((width - 1).try_into().unwrap(), 0, call);
88 ctx.smt.display(output_care_bits).to_string();
89
90 for (name, ty) in &ctx.additional_decls {
92 ctx.smt.declare_const(name, *ty).unwrap();
93 }
94 if ctx.additional_assumptions.len() > 1 {
95 ctx.smt
96 .assert(ctx.smt.and_many(ctx.additional_assumptions.clone()))
97 .unwrap();
98 }
99
100 ctx.smt.push().unwrap();
102 ctx.smt
103 .assert(ctx.smt.eq(output_care_bits, ctx.smt.atom(output)))
104 .unwrap();
105 if !matches!(ctx.smt.check(), Ok(Response::Sat)) {
106 ctx.smt.pop().unwrap();
109 assert!(matches!(ctx.smt.check(), Ok(Response::Sat)));
111
112 let model = ctx.smt.get_model().unwrap();
113 println!("{}", ctx.smt.display(model));
114
115 let val = ctx.smt.get_value(vec![output_care_bits]).unwrap()[0].1;
117
118 panic!("Expected {}, got {}", output, ctx.display_hex_to_bin(val));
119 } else {
120 ctx.smt.pop().unwrap();
121 }
122
123 ctx.smt.push().unwrap();
125 ctx.smt
126 .assert(
127 ctx.smt
128 .not(ctx.smt.eq(output_care_bits, ctx.smt.atom(output))),
129 )
130 .unwrap();
131 if !matches!(ctx.smt.check(), Ok(Response::Unsat)) {
132 let model = ctx.smt.get_model().unwrap();
133 println!("{}", ctx.smt.display(model));
134
135 let val = ctx.smt.get_value(vec![output_care_bits]).unwrap()[0].1;
137 panic!(
138 "Multiple possible outputs! Expected only {}, got {}",
139 output,
140 ctx.display_hex_to_bin(val)
141 );
142 }
143 ctx.smt.pop().unwrap();
144 }
145
146 fn check(ctx: &SolverCtx, expr: SExpr, expected: &str) {
147 let expr_s = format!("{}", ctx.smt.display(expr));
148 assert_eq!(expr_s, expected);
149 }
150
151 #[test]
152 fn rev1_test() {
153 let mut ctx = get_ctx();
154
155 let x = ctx.smt.atom("x");
156 let res = rev::rev1(&mut ctx, x, 42);
157
158 check(&ctx, res, "(concat fresh0 rev1ret_42)");
159 check(&ctx, ctx.additional_decls[0].1, "(_ BitVec 1)");
160 check(
161 &ctx,
162 ctx.additional_assumptions[0],
163 "(= rev1ret_42 ((_ extract 0 0) x))",
164 );
165 }
166
167 #[test]
168 fn test_rev8_with_solver() {
169 check_unary_encoding_with_solver("rev", "#b01010101", "#b10101010", 8);
170 check_unary_encoding_with_solver("rev", "#b11110000", "#b00001111", 8);
171 check_unary_encoding_with_solver("rev", "#b00000000", "#b00000000", 8);
172 check_unary_encoding_with_solver("rev", "#b11111111", "#b11111111", 8);
173 }
174
175 #[test]
176 fn test_rev16_with_solver() {
177 check_unary_encoding_with_solver("rev", "#b0101010101010101", "#b1010101010101010", 16);
178 check_unary_encoding_with_solver("rev", "#b1111111100000000", "#b0000000011111111", 16);
179 check_unary_encoding_with_solver("rev", "#b0000000000000000", "#b0000000000000000", 16);
180 check_unary_encoding_with_solver("rev", "#b1111111111111111", "#b1111111111111111", 16);
181 }
182
183 #[test]
184 fn test_rev32_with_solver() {
185 check_unary_encoding_with_solver(
186 "rev",
187 "#b01010101010101010101010101010101",
188 "#b10101010101010101010101010101010",
189 32,
190 );
191 check_unary_encoding_with_solver(
192 "rev",
193 "#b11111111111111110000000000000000",
194 "#b00000000000000001111111111111111",
195 32,
196 );
197 check_unary_encoding_with_solver(
198 "rev",
199 "#b00000000000000000000000000000000",
200 "#b00000000000000000000000000000000",
201 32,
202 );
203 check_unary_encoding_with_solver(
204 "rev",
205 "#b11111111111111111111111111111111",
206 "#b11111111111111111111111111111111",
207 32,
208 );
209 }
210
211 #[test]
212 fn test_rev64_with_solver() {
213 check_unary_encoding_with_solver(
214 "rev",
215 "#b0101010101010101010101010101010101010101010101010101010101010101",
216 "#b1010101010101010101010101010101010101010101010101010101010101010",
217 64,
218 );
219 check_unary_encoding_with_solver(
220 "rev",
221 "#b1111111111111111111111111111111100000000000000000000000000000000",
222 "#b0000000000000000000000000000000011111111111111111111111111111111",
223 64,
224 );
225 check_unary_encoding_with_solver(
226 "rev",
227 "#b0000000000000000000000000000000000000000000000000000000000000000",
228 "#b0000000000000000000000000000000000000000000000000000000000000000",
229 64,
230 );
231 check_unary_encoding_with_solver(
232 "rev",
233 "#b1111111111111111111111111111111111111111111111111111111111111111",
234 "#b1111111111111111111111111111111111111111111111111111111111111111",
235 64,
236 );
237 }
238
239 #[test]
240 fn test_clz8_with_solver() {
241 check_unary_encoding_with_solver("clz", "#b00000000", "#b00001000", 8);
242 check_unary_encoding_with_solver("clz", "#b01111111", "#b00000001", 8);
243 check_unary_encoding_with_solver("clz", "#b11111111", "#b00000000", 8);
244 }
245
246 #[test]
247 fn test_clz16_with_solver() {
248 check_unary_encoding_with_solver("clz", "#b0000000000000000", "#b0000000000010000", 16);
249 check_unary_encoding_with_solver("clz", "#b0000000000000001", "#b0000000000001111", 16);
250 check_unary_encoding_with_solver("clz", "#b0111111111111111", "#b0000000000000001", 16);
251 check_unary_encoding_with_solver("clz", "#b1111111111111111", "#b0000000000000000", 16);
252 }
253
254 #[test]
255 fn test_clz32_with_solver() {
256 check_unary_encoding_with_solver(
257 "clz",
258 "#b00000000000000000000000000000000",
259 "#b00000000000000000000000000100000",
260 32,
261 );
262 check_unary_encoding_with_solver(
263 "clz",
264 "#b00000000000000000000000000000001",
265 "#b00000000000000000000000000011111",
266 32,
267 );
268 check_unary_encoding_with_solver(
269 "clz",
270 "#b01000000000000000000000000000000",
271 "#b00000000000000000000000000000001",
272 32,
273 );
274 check_unary_encoding_with_solver(
275 "clz",
276 "#b11111111111111111111111111111111",
277 "#b00000000000000000000000000000000",
278 32,
279 );
280 }
281
282 #[test]
283 fn test_clz64_with_solver() {
284 check_unary_encoding_with_solver(
285 "clz",
286 "#b0000000000000000000000000000000000000000000000000000000000000000",
287 "#b0000000000000000000000000000000000000000000000000000000001000000",
288 64,
289 );
290 check_unary_encoding_with_solver(
291 "clz",
292 "#b0000000000000000000000000000000000000000000000000000000000000001",
293 "#b0000000000000000000000000000000000000000000000000000000000111111",
294 64,
295 );
296 check_unary_encoding_with_solver(
297 "clz",
298 "#b0100000000000000000000000000000000000000000000000000000000000000",
299 "#b0000000000000000000000000000000000000000000000000000000000000001",
300 64,
301 );
302 check_unary_encoding_with_solver(
303 "clz",
304 "#b1111111111111111111111111111111111111111111111111111111111111111",
305 "#b0000000000000000000000000000000000000000000000000000000000000000",
306 64,
307 );
308 }
309
310 #[test]
311 fn test_cls8_with_solver() {
312 check_unary_encoding_with_solver("cls", "#b00000000", "#b00000111", 8);
313 check_unary_encoding_with_solver("cls", "#b01111111", "#b00000000", 8);
314 check_unary_encoding_with_solver("cls", "#b00111111", "#b00000001", 8);
315 check_unary_encoding_with_solver("cls", "#b11000000", "#b00000001", 8);
316 check_unary_encoding_with_solver("cls", "#b11111111", "#b00000111", 8);
317 }
318
319 #[test]
320 fn test_cls16_with_solver() {
321 check_unary_encoding_with_solver("cls", "#b0000000000000000", "#b0000000000001111", 16);
322 check_unary_encoding_with_solver("cls", "#b0111111111111111", "#b0000000000000000", 16);
323 check_unary_encoding_with_solver("cls", "#b0011111111111111", "#b0000000000000001", 16);
324 check_unary_encoding_with_solver("cls", "#b1111111111111111", "#b0000000000001111", 16);
325 }
326
327 #[test]
328 fn test_cls32_with_solver() {
329 check_unary_encoding_with_solver(
330 "cls",
331 "#b00000000000000000000000000000000",
332 "#b00000000000000000000000000011111",
333 32,
334 );
335 check_unary_encoding_with_solver(
336 "cls",
337 "#b01111111111111111111111111111111",
338 "#b00000000000000000000000000000000",
339 32,
340 );
341 check_unary_encoding_with_solver(
342 "cls",
343 "#b00100000000000000000000000000000",
344 "#b00000000000000000000000000000001",
345 32,
346 );
347 check_unary_encoding_with_solver(
348 "cls",
349 "#b11111111111111111111111111111111",
350 "#b00000000000000000000000000011111",
351 32,
352 );
353 }
354
355 #[test]
356 fn test_cls64_with_solver() {
357 check_unary_encoding_with_solver(
358 "cls",
359 "#b0000000000000000000000000000000000000000000000000000000000000000",
360 "#b0000000000000000000000000000000000000000000000000000000000111111",
361 64,
362 );
363 check_unary_encoding_with_solver(
364 "cls",
365 "#b0010000000000000000000000000000000000000000000000000000000000000",
366 "#b0000000000000000000000000000000000000000000000000000000000000001",
367 64,
368 );
369 check_unary_encoding_with_solver(
370 "cls",
371 "#b0111111111111111111111111111111111111111111111111111111111111111",
372 "#b0000000000000000000000000000000000000000000000000000000000000000",
373 64,
374 );
375 check_unary_encoding_with_solver(
376 "cls",
377 "#b1111111111111111111111111111111111111111111111111111111111111111",
378 "#b0000000000000000000000000000000000000000000000000000000000111111",
379 64,
380 );
381 }
382
383 #[test]
384 fn test_popcnt_8_with_solver() {
385 check_unary_encoding_with_solver("popcnt", "#b00000000", "#b00000000", 8);
386 check_unary_encoding_with_solver("popcnt", "#b11111111", "#b00001000", 8);
387 check_unary_encoding_with_solver("popcnt", "#b01010101", "#b00000100", 8);
388 }
389
390 fn check_subs_with_solver(width: usize, x_str: &str, y_str: &str, output: &str) {
391 let mut ctx = get_ctx();
392
393 let ty = ctx.smt.bit_vec_sort(ctx.smt.numeral(width));
395 let x = ctx.declare("x".to_string(), ty);
396 let y = ctx.declare("y".to_string(), ty);
397
398 ctx.additional_assumptions
400 .push(ctx.smt.eq(x, ctx.smt.atom(x_str)));
401 ctx.additional_assumptions
402 .push(ctx.smt.eq(y, ctx.smt.atom(y_str)));
403
404 let call = subs::subs(&mut ctx, width, x, y, 0);
406
407 check_encoding_with_solver(ctx, call, output, 68)
409 }
410
411 #[test]
412 fn test_subs_32_with_solver() {
413 check_subs_with_solver(
414 32,
415 "#b00000000000000000000000000000000",
416 "#b00000000000000000000000000000000",
417 "#b01100000000000000000000000000000000000000000000000000000000000000000",
418 );
419
420 check_subs_with_solver(
421 32,
422 "#b11111111111111111111111111111111",
423 "#b00000000000000000000000000000000",
424 "#b10100000000000000000000000000000000011111111111111111111111111111111",
425 );
426
427 check_subs_with_solver(
428 32,
429 "#b10000000000010000000000000000000",
430 "#b00100111110000100011111110111000",
431 "#b00110000000000000000000000000000000001011000010001011100000001001000",
432 );
433 }
434
435 #[test]
436 fn test_subs_64_with_solver() {
437 check_subs_with_solver(
438 64,
439 "#b0000000000000000000000000000000000000000000000000000000000000000",
440 "#b0000000000000000000000000000000000000000000000000000000000000000",
441 "#b01100000000000000000000000000000000000000000000000000000000000000000",
442 );
443 }
444}