1use std::borrow::{Borrow, BorrowMut};
35use std::collections::{HashMap, HashSet};
36use std::io::Write;
37
38use crate::bitvector::{write_bits64, BV};
39use crate::ir::{Name, Symtab, Val, HAVE_EXCEPTION};
40use crate::smt::smtlib::*;
41use crate::smt::Event::*;
42use crate::smt::{Accessor, Event, Sym};
43use crate::zencode;
44
45#[allow(clippy::unneeded_field_pattern)]
50pub fn renumber_event<B>(event: &mut Event<B>, i: u32, total: u32) {
51 assert!(i < total);
52 use Event::*;
53 match event {
54 Smt(def) => renumber_def(def, i, total),
55 Fork(_, v, _) | Sleeping(v) => *v = Sym { id: (v.id * total) + i },
56 ReadReg(_, _, value) | WriteReg(_, _, value) | Instr(value) => renumber_val(value, i, total),
57 Branch { address } => renumber_val(address, i, total),
58 Barrier { barrier_kind } => renumber_val(barrier_kind, i, total),
59 ReadMem { value, read_kind, address, bytes: _, tag_value, kind: _ } => {
60 renumber_val(value, i, total);
61 renumber_val(read_kind, i, total);
62 renumber_val(address, i, total);
63 if let Some(v) = tag_value {
64 renumber_val(v, i, total);
65 }
66 }
67 WriteMem { value: v, write_kind, address, data, bytes: _, tag_value, kind: _ } => {
68 *v = Sym { id: (v.id * total) + i };
69 renumber_val(write_kind, i, total);
70 renumber_val(address, i, total);
71 renumber_val(data, i, total);
72 if let Some(v) = tag_value {
73 renumber_val(v, i, total);
74 }
75 }
76 CacheOp { cache_op_kind, address } => {
77 renumber_val(cache_op_kind, i, total);
78 renumber_val(address, i, total);
79 }
80 Cycle | SleepRequest | WakeupRequest | MarkReg { .. } => (),
81 }
82}
83
84fn renumber_exp(exp: &mut Exp, i: u32, total: u32) {
85 exp.modify(
86 &(|exp| {
87 if let Exp::Var(v) = exp {
88 *v = Sym { id: (v.id * total) + i }
89 }
90 }),
91 )
92}
93
94fn renumber_val<B>(val: &mut Val<B>, i: u32, total: u32) {
95 use Val::*;
96 match val {
97 Symbolic(v) => *v = Sym { id: (v.id * total) + i },
98 I64(_) | I128(_) | Bool(_) | Bits(_) | Enum(_) | String(_) | Unit | Ref(_) | Poison => (),
99 List(vals) | Vector(vals) => vals.iter_mut().for_each(|val| renumber_val(val, i, total)),
100 Struct(fields) => fields.iter_mut().for_each(|(_, val)| renumber_val(val, i, total)),
101 Ctor(_, val) => renumber_val(val, i, total),
102 }
103}
104
105fn renumber_def(def: &mut Def, i: u32, total: u32) {
106 use Def::*;
107 match def {
108 DeclareConst(v, _) | DeclareFun(v, _, _) | DefineEnum(v, _) => *v = Sym { id: (v.id * total) + i },
109 DefineConst(v, exp) => {
110 *v = Sym { id: (v.id * total) + i };
111 renumber_exp(exp, i, total)
112 }
113 Assert(exp) => renumber_exp(exp, i, total),
114 }
115}
116
117fn uses_in_exp(uses: &mut HashMap<Sym, u32>, exp: &Exp) {
119 use Exp::*;
120 match exp {
121 Var(v) => {
122 uses.insert(*v, uses.get(&v).unwrap_or(&0) + 1);
123 }
124 Bits(_) | Bits64(_) | Enum(_) | Bool(_) => (),
125 Not(exp) | Bvnot(exp) | Bvneg(exp) | Extract(_, _, exp) | ZeroExtend(_, exp) | SignExtend(_, exp) => {
126 uses_in_exp(uses, exp)
127 }
128 Eq(lhs, rhs)
129 | Neq(lhs, rhs)
130 | And(lhs, rhs)
131 | Or(lhs, rhs)
132 | Bvand(lhs, rhs)
133 | Bvor(lhs, rhs)
134 | Bvxor(lhs, rhs)
135 | Bvnand(lhs, rhs)
136 | Bvnor(lhs, rhs)
137 | Bvxnor(lhs, rhs)
138 | Bvadd(lhs, rhs)
139 | Bvsub(lhs, rhs)
140 | Bvmul(lhs, rhs)
141 | Bvudiv(lhs, rhs)
142 | Bvsdiv(lhs, rhs)
143 | Bvurem(lhs, rhs)
144 | Bvsrem(lhs, rhs)
145 | Bvsmod(lhs, rhs)
146 | Bvult(lhs, rhs)
147 | Bvslt(lhs, rhs)
148 | Bvule(lhs, rhs)
149 | Bvsle(lhs, rhs)
150 | Bvuge(lhs, rhs)
151 | Bvsge(lhs, rhs)
152 | Bvugt(lhs, rhs)
153 | Bvsgt(lhs, rhs)
154 | Bvshl(lhs, rhs)
155 | Bvlshr(lhs, rhs)
156 | Bvashr(lhs, rhs)
157 | Concat(lhs, rhs) => {
158 uses_in_exp(uses, lhs);
159 uses_in_exp(uses, rhs)
160 }
161 Ite(cond, then_exp, else_exp) => {
162 uses_in_exp(uses, cond);
163 uses_in_exp(uses, then_exp);
164 uses_in_exp(uses, else_exp)
165 }
166 App(f, args) => {
167 uses.insert(*f, uses.get(&f).unwrap_or(&0) + 1);
168 for arg in args {
169 uses_in_exp(uses, arg);
170 }
171 }
172 Select(array, index) => {
173 uses_in_exp(uses, array);
174 uses_in_exp(uses, index)
175 }
176 Store(array, index, val) => {
177 uses_in_exp(uses, array);
178 uses_in_exp(uses, index);
179 uses_in_exp(uses, val)
180 }
181 }
182}
183
184fn uses_in_value<B>(uses: &mut HashMap<Sym, u32>, val: &Val<B>) {
185 use Val::*;
186 match val {
187 Symbolic(v) => {
188 uses.insert(*v, uses.get(&v).unwrap_or(&0) + 1);
189 }
190 I64(_) | I128(_) | Bool(_) | Bits(_) | Enum(_) | String(_) | Unit | Ref(_) | Poison => (),
191 List(vals) | Vector(vals) => vals.iter().for_each(|val| uses_in_value(uses, val)),
192 Struct(fields) => fields.iter().for_each(|(_, val)| uses_in_value(uses, val)),
193 Ctor(_, val) => uses_in_value(uses, val),
194 }
195}
196
197pub type Taints = HashSet<(Name, Vec<Accessor>)>;
198
199pub struct EventReferences {
203 references: HashMap<Sym, HashMap<Sym, u32>>,
204}
205
206impl EventReferences {
207 pub fn from_events<B, E: Borrow<Event<B>>>(events: &[E]) -> Self {
208 let mut references = HashMap::new();
209
210 for event in events.iter() {
211 if let Smt(Def::DefineConst(id, exp)) = event.borrow() {
212 let mut uses = HashMap::new();
213 uses_in_exp(&mut uses, exp);
214 references.insert(*id, uses);
215 }
216 }
217 EventReferences { references }
218 }
219
220 pub fn dependencies(&self, symbol: Sym) -> HashSet<Sym> {
224 let empty_map = HashMap::new();
225 let mut deps = HashSet::new();
227 deps.insert(symbol);
228 let mut seen = HashSet::new();
231
232 loop {
233 let mut next = HashSet::new();
234
235 for symbol in deps.iter() {
236 if !seen.contains(symbol) {
237 let immediate_deps = self.references.get(&symbol).unwrap_or_else(|| &empty_map);
238 for k in immediate_deps.keys() {
239 next.insert(*k);
240 }
241 seen.insert(*symbol);
242 }
243 }
244
245 if next.is_empty() {
247 break;
248 } else {
249 for symbol in next.iter() {
250 deps.insert(*symbol);
251 }
252 }
253 }
254
255 deps
256 }
257
258 pub fn taints<B: BV, E: Borrow<Event<B>>>(&self, symbol: Sym, events: &[E]) -> (Taints, bool) {
263 let mut taints = HashSet::new();
264 let mut memory = false;
265 self.collect_taints(symbol, events, &mut taints, &mut memory);
266 (taints, memory)
267 }
268
269 pub fn value_taints<B: BV, E: Borrow<Event<B>>>(&self, val: &Val<B>, events: &[E]) -> (Taints, bool) {
271 let mut taints = HashSet::new();
272 let mut memory = false;
273 self.collect_value_taints(val, events, &mut taints, &mut memory);
274 (taints, memory)
275 }
276
277 pub fn collect_taints<B: BV, E: Borrow<Event<B>>>(
278 &self,
279 symbol: Sym,
280 events: &[E],
281 taints: &mut Taints,
282 memory: &mut bool,
283 ) {
284 let deps = self.dependencies(symbol);
285
286 for event in events.iter() {
287 match event.borrow() {
288 ReadReg(reg, accessor, value) => {
289 let mut uses = HashMap::new();
290 uses_in_value(&mut uses, value);
291 for (taint, _) in uses.iter() {
292 if deps.contains(taint) {
293 taints.insert((*reg, accessor.clone()));
294 break;
295 }
296 }
297 }
298
299 ReadMem { value: Val::Symbolic(taint), .. } if deps.contains(taint) => *memory = true,
300 ReadMem { tag_value: Some(Val::Symbolic(taint)), .. } if deps.contains(taint) => *memory = true,
301
302 _ => (),
303 }
304 }
305 }
306
307 pub fn collect_value_taints<B: BV, E: Borrow<Event<B>>>(
308 &self,
309 val: &Val<B>,
310 events: &[E],
311 taints: &mut Taints,
312 memory: &mut bool,
313 ) {
314 for symbol in val.symbolic_variables() {
315 self.collect_taints(symbol, events, taints, memory)
316 }
317 }
318}
319
320#[allow(clippy::unneeded_field_pattern)]
321fn calculate_uses<B, E: Borrow<Event<B>>>(events: &[E]) -> HashMap<Sym, u32> {
322 let mut uses: HashMap<Sym, u32> = HashMap::new();
323
324 for event in events.iter().rev() {
325 use Event::*;
326 match event.borrow() {
327 Smt(Def::DeclareConst(_, _)) => (),
328 Smt(Def::DeclareFun(_, _, _)) => (),
329 Smt(Def::DefineConst(_, exp)) => uses_in_exp(&mut uses, exp),
330 Smt(Def::DefineEnum(_, _)) => (),
331 Smt(Def::Assert(exp)) => uses_in_exp(&mut uses, exp),
332 ReadReg(_, _, val) => uses_in_value(&mut uses, val),
333 WriteReg(_, _, val) => uses_in_value(&mut uses, val),
334 ReadMem { value: val, read_kind, address, bytes: _, tag_value, kind: _ } => {
335 uses_in_value(&mut uses, val);
336 uses_in_value(&mut uses, read_kind);
337 uses_in_value(&mut uses, address);
338 if let Some(v) = tag_value {
339 uses_in_value(&mut uses, v);
340 }
341 }
342 WriteMem { value: sym, write_kind, address, data, bytes: _, tag_value, kind: _ } => {
343 uses.insert(*sym, uses.get(&sym).unwrap_or(&0) + 1);
344 uses_in_value(&mut uses, write_kind);
345 uses_in_value(&mut uses, address);
346 uses_in_value(&mut uses, data);
347 if let Some(v) = tag_value {
348 uses_in_value(&mut uses, v);
349 }
350 }
351 Branch { address } => uses_in_value(&mut uses, address),
352 Barrier { barrier_kind } => uses_in_value(&mut uses, barrier_kind),
353 CacheOp { cache_op_kind, address } => {
354 uses_in_value(&mut uses, cache_op_kind);
355 uses_in_value(&mut uses, address)
356 }
357 Fork(_, sym, _) => {
358 uses.insert(*sym, uses.get(&sym).unwrap_or(&0) + 1);
359 }
360 Cycle => (),
361 Instr(val) => uses_in_value(&mut uses, val),
362 Sleeping(sym) => {
363 uses.insert(*sym, uses.get(&sym).unwrap_or(&0) + 1);
364 }
365 MarkReg { .. } => (),
366 WakeupRequest => (),
367 SleepRequest => (),
368 }
369 }
370
371 uses
372}
373
374fn calculate_required_uses<B, E: Borrow<Event<B>>>(events: &[E]) -> HashMap<Sym, u32> {
377 let mut uses: HashMap<Sym, u32> = HashMap::new();
378
379 for event in events.iter().rev() {
380 use Event::*;
381 match event.borrow() {
382 Smt(Def::DeclareConst(sym, _)) => {
383 uses.insert(*sym, uses.get(&sym).unwrap_or(&0) + 1);
384 }
385 Smt(Def::DeclareFun(sym, _, _)) => {
386 uses.insert(*sym, uses.get(&sym).unwrap_or(&0) + 1);
387 }
388 Smt(Def::DefineEnum(sym, _)) => {
389 uses.insert(*sym, uses.get(&sym).unwrap_or(&0) + 1);
390 }
391 Smt(_) => (),
392 ReadReg(_, _, val) => uses_in_value(&mut uses, val),
393 WriteReg(_, _, val) => uses_in_value(&mut uses, val),
394 ReadMem { value: val, read_kind, address, bytes: _, tag_value, kind: _ } => {
395 uses_in_value(&mut uses, val);
396 uses_in_value(&mut uses, read_kind);
397 uses_in_value(&mut uses, address);
398 if let Some(v) = tag_value {
399 uses_in_value(&mut uses, v);
400 }
401 }
402 WriteMem { value: sym, write_kind, address, data, bytes: _, tag_value, kind: _ } => {
403 uses.insert(*sym, uses.get(&sym).unwrap_or(&0) + 1);
404 uses_in_value(&mut uses, write_kind);
405 uses_in_value(&mut uses, address);
406 uses_in_value(&mut uses, data);
407 if let Some(v) = tag_value {
408 uses_in_value(&mut uses, v);
409 }
410 }
411 Branch { address } => uses_in_value(&mut uses, address),
412 Barrier { barrier_kind } => uses_in_value(&mut uses, barrier_kind),
413 CacheOp { cache_op_kind, address } => {
414 uses_in_value(&mut uses, cache_op_kind);
415 uses_in_value(&mut uses, address)
416 }
417 Fork(_, sym, _) => {
418 uses.insert(*sym, uses.get(&sym).unwrap_or(&0) + 1);
419 }
420 Cycle => (),
421 Instr(val) => uses_in_value(&mut uses, val),
422 Sleeping(sym) => {
423 uses.insert(*sym, uses.get(&sym).unwrap_or(&0) + 1);
424 }
425 MarkReg { .. } => (),
426 WakeupRequest => (),
427 SleepRequest => (),
428 }
429 }
430
431 uses
432}
433
434fn remove_unused_pass<B, E: Borrow<Event<B>>>(events: &mut Vec<E>) -> u32 {
435 let uses = calculate_uses(&events);
436 let mut removed = 0;
437
438 events.retain(|event| match event.borrow() {
439 Smt(Def::DeclareConst(v, _)) => {
440 if uses.contains_key(v) {
441 true
442 } else {
443 removed += 1;
444 false
445 }
446 }
447 Smt(Def::DefineConst(v, _)) => {
448 if uses.contains_key(v) {
449 true
450 } else {
451 removed += 1;
452 false
453 }
454 }
455 _ => true,
456 });
457
458 removed
459}
460
461pub fn hide_initialization<B: BV, E: Borrow<Event<B>>>(events: &mut Vec<E>) {
465 let mut keep = vec![true; events.len()];
466 let mut init_cycle = true;
467 for (i, event) in events.iter().enumerate().rev() {
468 match event.borrow() {
469 WriteReg { .. } if init_cycle => keep[i] = false,
470 ReadReg { .. } if init_cycle => keep[i] = false,
471 Cycle => init_cycle = false,
472 _ => (),
473 }
474 }
475 let mut i = 0;
476 events.retain(|_| {
477 i += 1;
478 keep[i - 1]
479 })
480}
481
482pub fn remove_unused<B: BV, E: Borrow<Event<B>>>(events: &mut Vec<E>) {
485 loop {
486 if remove_unused_pass(events) == 0 {
487 break;
488 }
489 }
490}
491
492pub fn propagate_forwards_used_once<B: BV, E: BorrowMut<Event<B>>>(events: &mut Vec<E>) {
496 let uses = calculate_uses(&events);
497 let required_uses = calculate_required_uses(&events);
498
499 let mut substs: HashMap<Sym, Option<Exp>> = HashMap::new();
500
501 for (sym, count) in uses {
502 if count == 1 && !required_uses.contains_key(&sym) {
503 substs.insert(sym, None);
504 }
505 }
506
507 let mut keep = vec![true; events.len()];
508
509 for (i, event) in events.iter_mut().enumerate().rev() {
510 match event.borrow_mut() {
511 Event::Smt(Def::DefineConst(sym, exp)) => {
512 exp.subst_once_in_place(&mut substs);
513
514 if substs.contains_key(&sym) {
515 let exp = std::mem::replace(exp, Exp::Bool(false));
516 keep[i] = false;
517 substs.insert(*sym, Some(exp));
518 }
519 }
520 Event::Smt(Def::Assert(exp)) => exp.subst_once_in_place(&mut substs),
521 _ => (),
522 }
523 }
524
525 let mut i = 0;
526 events.retain(|_| {
527 i += 1;
528 keep[i - 1]
529 })
530}
531
532pub fn eval<B: BV, E: BorrowMut<Event<B>>>(events: &mut Vec<E>) {
534 for event in events.iter_mut() {
535 match event.borrow_mut() {
536 Event::Smt(Def::DefineConst(_, exp)) | Event::Smt(Def::Assert(exp)) => {
537 let e = std::mem::replace(exp, Exp::Bool(false));
538 *exp = e.eval();
539 }
540 _ => (),
541 }
542 }
543}
544
545pub fn commute_extract<B: BV, E: BorrowMut<Event<B>>>(events: &mut Vec<E>) {
559 for event in events.iter_mut() {
560 match event.borrow_mut() {
561 Event::Smt(Def::DefineConst(_, exp)) | Event::Smt(Def::Assert(exp)) => exp.modify_top_down(&Exp::commute_extract),
562 _ => (),
563 }
564 }
565}
566
567fn accessor_to_string(acc: &[Accessor], symtab: &Symtab) -> String {
568 acc.iter()
569 .map(|elem| elem.to_string(symtab))
570 .fold(None, |acc, elem| if let Some(prefix) = acc { Some(format!("{} {}", prefix, elem)) } else { Some(elem) })
571 .map_or("nil".to_string(), |acc| format!("({})", acc))
572}
573
574pub struct WriteOpts {
576 pub variable_prefix: String,
578 pub enum_prefix: String,
580 pub types: bool,
582 pub just_smt: bool,
585 pub define_enum: bool,
588}
589
590impl WriteOpts {
591 pub fn smtlib() -> Self {
592 WriteOpts {
593 variable_prefix: "v".to_string(),
594 enum_prefix: "e".to_string(),
595 types: true,
596 just_smt: true,
597 define_enum: false,
598 }
599 }
600}
601
602impl Default for WriteOpts {
603 fn default() -> Self {
604 WriteOpts {
605 variable_prefix: "v".to_string(),
606 enum_prefix: "e".to_string(),
607 types: false,
608 just_smt: false,
609 define_enum: true,
610 }
611 }
612}
613
614fn write_bits(buf: &mut dyn Write, bits: &[bool]) -> std::io::Result<()> {
615 if bits.len() % 4 == 0 {
616 write!(buf, "#x")?;
617 for i in (0..(bits.len() / 4)).rev() {
618 let j = i * 4;
619 let hex = (if bits[j] { 0b0001 } else { 0 })
620 | (if bits[j + 1] { 0b0010 } else { 0 })
621 | (if bits[j + 2] { 0b0100 } else { 0 })
622 | (if bits[j + 3] { 0b1000 } else { 0 });
623 write!(buf, "{:x}", hex)?;
624 }
625 } else {
626 write!(buf, "#b")?;
627 for bit in bits.iter().rev() {
628 if *bit {
629 write!(buf, "1")?
630 } else {
631 write!(buf, "0")?
632 }
633 }
634 }
635 Ok(())
636}
637
638fn write_exp(buf: &mut dyn Write, exp: &Exp, opts: &WriteOpts, enums: &[usize]) -> std::io::Result<()> {
639 use Exp::*;
640 match exp {
641 Var(v) => write!(buf, "{}{}", opts.variable_prefix, v),
642 Bits(bv) => write_bits(buf, bv),
643 Bits64(bv) => write_bits64(buf, bv.lower_u64(), bv.len()),
644 Enum(e) => write!(buf, "{}{}_{}", opts.enum_prefix, enums[e.enum_id], e.member),
645 Bool(b) => write!(buf, "{}", b),
646 Eq(lhs, rhs) => write_binop(buf, "=", lhs, rhs, opts, enums),
647 Neq(lhs, rhs) => {
648 write!(buf, "(not ")?;
649 write_binop(buf, "=", lhs, rhs, opts, enums)?;
650 write!(buf, ")")
651 }
652 And(lhs, rhs) => write_binop(buf, "and", lhs, rhs, opts, enums),
653 Or(lhs, rhs) => write_binop(buf, "or", lhs, rhs, opts, enums),
654 Not(exp) => write_unop(buf, "not", exp, opts, enums),
655 Bvnot(exp) => write_unop(buf, "bvnot", exp, opts, enums),
656 Bvand(lhs, rhs) => write_binop(buf, "bvand", lhs, rhs, opts, enums),
657 Bvor(lhs, rhs) => write_binop(buf, "bvor", lhs, rhs, opts, enums),
658 Bvxor(lhs, rhs) => write_binop(buf, "bvxor", lhs, rhs, opts, enums),
659 Bvnand(lhs, rhs) => write_binop(buf, "bvnand", lhs, rhs, opts, enums),
660 Bvnor(lhs, rhs) => write_binop(buf, "bvnor", lhs, rhs, opts, enums),
661 Bvxnor(lhs, rhs) => write_binop(buf, "bvxnor", lhs, rhs, opts, enums),
662 Bvneg(exp) => write_unop(buf, "bvneg", exp, opts, enums),
663 Bvadd(lhs, rhs) => write_binop(buf, "bvadd", lhs, rhs, opts, enums),
664 Bvsub(lhs, rhs) => write_binop(buf, "bvsub", lhs, rhs, opts, enums),
665 Bvmul(lhs, rhs) => write_binop(buf, "bvmul", lhs, rhs, opts, enums),
666 Bvudiv(lhs, rhs) => write_binop(buf, "bvudiv", lhs, rhs, opts, enums),
667 Bvsdiv(lhs, rhs) => write_binop(buf, "bvsdiv", lhs, rhs, opts, enums),
668 Bvurem(lhs, rhs) => write_binop(buf, "bvurem", lhs, rhs, opts, enums),
669 Bvsrem(lhs, rhs) => write_binop(buf, "bvsrem", lhs, rhs, opts, enums),
670 Bvsmod(lhs, rhs) => write_binop(buf, "bvsmod", lhs, rhs, opts, enums),
671 Bvult(lhs, rhs) => write_binop(buf, "bvult", lhs, rhs, opts, enums),
672 Bvslt(lhs, rhs) => write_binop(buf, "bvslt", lhs, rhs, opts, enums),
673 Bvule(lhs, rhs) => write_binop(buf, "bvule", lhs, rhs, opts, enums),
674 Bvsle(lhs, rhs) => write_binop(buf, "bvsle", lhs, rhs, opts, enums),
675 Bvuge(lhs, rhs) => write_binop(buf, "bvuge", lhs, rhs, opts, enums),
676 Bvsge(lhs, rhs) => write_binop(buf, "bvsge", lhs, rhs, opts, enums),
677 Bvugt(lhs, rhs) => write_binop(buf, "bvugt", lhs, rhs, opts, enums),
678 Bvsgt(lhs, rhs) => write_binop(buf, "bvsgt", lhs, rhs, opts, enums),
679 Extract(i, j, exp) => {
680 write!(buf, "((_ extract {} {}) ", i, j)?;
681 write_exp(buf, exp, opts, enums)?;
682 write!(buf, ")")
683 }
684 ZeroExtend(n, exp) => {
685 write!(buf, "((_ zero_extend {}) ", n)?;
686 write_exp(buf, exp, opts, enums)?;
687 write!(buf, ")")
688 }
689 SignExtend(n, exp) => {
690 write!(buf, "((_ sign_extend {}) ", n)?;
691 write_exp(buf, exp, opts, enums)?;
692 write!(buf, ")")
693 }
694 Bvshl(lhs, rhs) => write_binop(buf, "bvshl", lhs, rhs, opts, enums),
695 Bvlshr(lhs, rhs) => write_binop(buf, "bvlshr", lhs, rhs, opts, enums),
696 Bvashr(lhs, rhs) => write_binop(buf, "bvashr", lhs, rhs, opts, enums),
697 Concat(lhs, rhs) => write_binop(buf, "concat", lhs, rhs, opts, enums),
698 Ite(cond, then_exp, else_exp) => {
699 write!(buf, "(ite ")?;
700 write_exp(buf, cond, opts, enums)?;
701 write!(buf, " ")?;
702 write_exp(buf, then_exp, opts, enums)?;
703 write!(buf, " ")?;
704 write_exp(buf, else_exp, opts, enums)?;
705 write!(buf, ")")
706 }
707 App(f, args) => {
708 write!(buf, "({}{}", opts.variable_prefix, f)?;
709 for arg in args {
710 write!(buf, " ")?;
711 write_exp(buf, arg, opts, enums)?;
712 }
713 write!(buf, ")")
714 }
715 Select(array, index) => write_binop(buf, "select", array, index, opts, enums),
716 Store(array, index, val) => {
717 write!(buf, "(store ")?;
718 write_exp(buf, array, opts, enums)?;
719 write!(buf, " ")?;
720 write_exp(buf, index, opts, enums)?;
721 write!(buf, " ")?;
722 write_exp(buf, val, opts, enums)?;
723 write!(buf, ")")
724 }
725 }
726}
727
728fn write_unop(buf: &mut dyn Write, op: &str, exp: &Exp, opts: &WriteOpts, enums: &[usize]) -> std::io::Result<()> {
729 write!(buf, "({} ", op)?;
730 write_exp(buf, exp, opts, enums)?;
731 write!(buf, ")")
732}
733
734fn write_binop(
735 buf: &mut dyn Write,
736 op: &str,
737 lhs: &Exp,
738 rhs: &Exp,
739 opts: &WriteOpts,
740 enums: &[usize],
741) -> std::io::Result<()> {
742 write!(buf, "({} ", op)?;
743 write_exp(buf, lhs, opts, enums)?;
744 write!(buf, " ")?;
745 write_exp(buf, rhs, opts, enums)?;
746 write!(buf, ")")
747}
748
749pub fn write_events_with_opts<B: BV>(
750 buf: &mut dyn Write,
751 events: &[Event<B>],
752 symtab: &Symtab,
753 opts: &WriteOpts,
754) -> std::io::Result<()> {
755 let mut tcx: HashMap<Sym, Ty> = HashMap::new();
756 let mut ftcx: HashMap<Sym, (Vec<Ty>, Ty)> = HashMap::new();
757 let mut enums: Vec<usize> = Vec::new();
758
759 if !opts.just_smt {
760 write!(buf, "(trace").unwrap();
761 }
762 for event in events.iter().filter(|ev| !opts.just_smt || ev.is_smt()) {
763 (match event {
764 Fork(n, _, loc) => write!(buf, "\n (branch {} \"{}\")", n, loc),
766
767 Smt(Def::DefineEnum(_, size)) if !opts.define_enum => {
768 enums.push(*size);
769 Ok(())
770 }
771
772 Smt(def) => {
773 if opts.just_smt {
774 writeln!(buf)?
775 } else {
776 write!(buf, "\n ")?;
777 }
778 match def {
779 Def::DeclareConst(v, ty) => {
780 tcx.insert(*v, ty.clone());
781 write!(buf, "(declare-const {}{} {})", opts.variable_prefix, v, ty)
782 }
783 Def::DeclareFun(v, arg_tys, result_ty) => {
784 ftcx.insert(*v, (arg_tys.clone(), result_ty.clone()));
785 write!(buf, "(declare_fun {}{} (", opts.variable_prefix, v)?;
786 for ty in arg_tys {
787 write!(buf, "{} ", ty)?
788 }
789 write!(buf, ") {})", result_ty)
790 }
791 Def::DefineConst(v, exp) => {
792 if opts.types {
793 let ty = exp.infer(&tcx, &ftcx).expect("SMT expression was badly-typed");
794 tcx.insert(*v, ty.clone());
795 write!(buf, "(define-const v{} {} ", v, ty)?;
796 write_exp(buf, exp, opts, &enums)?;
797 write!(buf, ")")
798 } else {
799 write!(buf, "(define-const v{} ", v)?;
800 write_exp(buf, exp, opts, &enums)?;
801 write!(buf, ")")
802 }
803 }
804 Def::DefineEnum(_, size) => {
805 if !opts.just_smt {
806 write!(buf, "(define-enum {})", size)?
807 }
808 enums.push(*size);
809 Ok(())
810 }
811 Def::Assert(exp) => {
812 write!(buf, "(assert ")?;
813 write_exp(buf, exp, opts, &enums)?;
814 write!(buf, ")")
815 }
816 }
817 }
818
819 ReadMem { value, read_kind, address, bytes, tag_value, kind: _ } => write!(
820 buf,
821 "\n (read-mem {} {} {} {} {})",
822 value.to_string(symtab),
823 read_kind.to_string(symtab),
824 address.to_string(symtab),
825 bytes,
826 match tag_value {
827 None => "None".to_string(),
828 Some(v) => format!("Some({})", v.to_string(symtab)),
829 }
830 ),
831
832 WriteMem { value, write_kind, address, data, bytes, tag_value, kind: _ } => write!(
833 buf,
834 "\n (write-mem v{} {} {} {} {} {})",
835 value,
836 write_kind.to_string(symtab),
837 address.to_string(symtab),
838 data.to_string(symtab),
839 bytes,
840 match tag_value {
841 None => "None".to_string(),
842 Some(v) => format!("Some({})", v.to_string(symtab)),
843 }
844 ),
845
846 Branch { address } => write!(buf, "\n (branch-address {})", address.to_string(symtab)),
847
848 Barrier { barrier_kind } => write!(buf, "\n (barrier {})", barrier_kind.to_string(symtab)),
849
850 CacheOp { cache_op_kind, address } => {
851 write!(buf, "\n (cache-op {} {})", cache_op_kind.to_string(symtab), address.to_string(symtab))
852 }
853
854 WriteReg(n, acc, v) => write!(
855 buf,
856 "\n (write-reg |{}| {} {})",
857 zencode::decode(symtab.to_str(*n)),
858 accessor_to_string(acc, symtab),
859 v.to_string(symtab)
860 ),
861
862 ReadReg(n, acc, v) => {
863 if *n == HAVE_EXCEPTION {
864 Ok(())
865 } else {
866 write!(
867 buf,
868 "\n (read-reg |{}| {} {})",
869 zencode::decode(symtab.to_str(*n)),
870 accessor_to_string(acc, symtab),
871 v.to_string(symtab)
872 )
873 }
874 }
875
876 MarkReg { regs, mark } => {
877 for reg in regs {
878 write!(buf, "\n (mark-reg |{}| \"{}\")", zencode::decode(symtab.to_str(*reg)), mark)?
879 }
880 Ok(())
881 }
882
883 Cycle => write!(buf, "\n (cycle)"),
884
885 Instr(value) => write!(buf, "\n (instr {})", value.to_string(symtab)),
886
887 Sleeping(value) => write!(buf, "\n (sleeping v{})", value),
888
889 SleepRequest => write!(buf, "\n (sleep-request)"),
890
891 WakeupRequest => write!(buf, "\n (wake-request)"),
892 })?
893 }
894 if !opts.just_smt {
895 writeln!(buf, ")")?;
896 }
897 Ok(())
898}
899
900pub fn write_events<B: BV>(buf: &mut dyn Write, events: &[Event<B>], symtab: &Symtab) {
901 write_events_with_opts(buf, events, symtab, &WriteOpts::default()).unwrap()
902}