1use serde::{Deserialize, Serialize};
45use std::collections::{HashMap, HashSet};
46use std::fmt;
47use std::hash::Hash;
48use std::sync::Arc;
49
50use crate::bitvector::{b64::B64, BV};
51use crate::error::ExecError;
52use crate::memory::Memory;
53use crate::primop::{Binary, Primops, Unary, Variadic};
54use crate::smt::{Solver, Sym};
55use crate::zencode;
56
57pub mod linearize;
58pub mod serialize;
59pub mod ssa;
60
61#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
62pub struct Name {
63 id: u32,
64}
65
66#[derive(Clone, Debug, Serialize, Deserialize)]
67pub enum Ty<A> {
68 I64,
69 I128,
70 AnyBits,
71 Bits(u32),
72 Unit,
73 Bool,
74 Bit,
75 String,
76 Real,
77 Enum(A),
78 Struct(A),
79 Union(A),
80 Vector(Box<Ty<A>>),
81 FixedVector(u32, Box<Ty<A>>),
82 List(Box<Ty<A>>),
83 Ref(Box<Ty<A>>),
84}
85
86#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
88pub enum Loc<A> {
89 Id(A),
90 Field(Box<Loc<A>>, A),
91 Addr(Box<Loc<A>>),
92}
93
94impl<A: Clone> Loc<A> {
95 pub fn id(&self) -> A {
96 match self {
97 Loc::Id(id) => id.clone(),
98 Loc::Field(loc, _) | Loc::Addr(loc) => loc.id(),
99 }
100 }
101
102 pub fn id_mut(&mut self) -> &mut A {
103 match self {
104 Loc::Id(id) => id,
105 Loc::Field(loc, _) | Loc::Addr(loc) => loc.id_mut(),
106 }
107 }
108}
109
110#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
111pub enum Op {
112 Not,
113 Or,
114 And,
115 Eq,
116 Neq,
117 Lteq,
118 Lt,
119 Gteq,
120 Gt,
121 Add,
122 Sub,
123 Slice(u32),
124 SetSlice,
125 Signed(u32),
126 Unsigned(u32),
127 ZeroExtend(u32),
128 Bvnot,
129 Bvor,
130 Bvxor,
131 Bvand,
132 Bvadd,
133 Bvsub,
134 Bvaccess,
135 Concat,
136 Head,
137 Tail,
138}
139
140#[derive(Copy, Clone, Debug, PartialEq, Eq)]
141pub struct EnumMember {
142 pub enum_id: usize,
143 pub member: usize,
144}
145
146#[derive(Clone, Debug)]
150pub enum Val<B> {
151 Symbolic(Sym),
152 I64(i64),
153 I128(i128),
154 Bool(bool),
155 Bits(B),
156 String(String),
157 Unit,
158 Vector(Vec<Val<B>>),
159 List(Vec<Val<B>>),
160 Enum(EnumMember),
161 Struct(HashMap<Name, Val<B>>),
162 Ctor(Name, Box<Val<B>>),
163 Ref(Name),
164 Poison,
165}
166
167impl<B: BV> Val<B> {
168 fn collect_symbolic_variables(&self, vars: &mut HashSet<Sym>) {
169 use Val::*;
170 match self {
171 Symbolic(v) => {
172 vars.insert(*v);
173 }
174 I64(_) | I128(_) | Bool(_) | Bits(_) | Enum(_) | String(_) | Unit | Ref(_) | Poison => (),
175 Vector(vals) | List(vals) => vals.iter().for_each(|val| val.collect_symbolic_variables(vars)),
176 Struct(vals) => vals.iter().for_each(|(_, val)| val.collect_symbolic_variables(vars)),
177 Ctor(_, val) => val.collect_symbolic_variables(vars),
178 }
179 }
180
181 pub fn symbolic_variables(&self) -> HashSet<Sym> {
182 let mut vars = HashSet::new();
183 self.collect_symbolic_variables(&mut vars);
184 vars
185 }
186
187 pub fn is_symbolic(&self) -> bool {
188 !self.symbolic_variables().is_empty()
189 }
190
191 pub fn as_bits(&self) -> Option<&B> {
192 match self {
193 Val::Bits(bv) => Some(bv),
194 _ => None,
195 }
196 }
197
198 pub fn to_string(&self, symtab: &Symtab) -> String {
199 use Val::*;
200 match self {
201 Symbolic(v) => format!("v{}", v),
202 I64(n) => format!("(_ bv{} 64)", n),
203 I128(n) => format!("(_ bv{} 128)", n),
204 Bool(b) => format!("{}", b),
205 Bits(bv) => format!("{}", bv),
206 String(s) => format!("\"{}\"", s),
207 Enum(EnumMember { enum_id, member }) => format!("e{}_{}", enum_id, member),
208 Unit => "(_ unit)".to_string(),
209 List(vec) => {
210 let vec =
211 vec.iter()
212 .map(|elem| elem.to_string(symtab))
213 .fold(None, |acc, elem| {
214 if let Some(prefix) = acc {
215 Some(format!("{} {}", prefix, elem))
216 } else {
217 Some(elem)
218 }
219 })
220 .unwrap_or_else(|| "nil".to_string());
221 format!("(_ list {})", vec)
222 }
223 Vector(vec) => {
224 let vec =
225 vec.iter()
226 .map(|elem| elem.to_string(symtab))
227 .fold(None, |acc, elem| {
228 if let Some(prefix) = acc {
229 Some(format!("{} {}", prefix, elem))
230 } else {
231 Some(elem)
232 }
233 })
234 .unwrap_or_else(|| "nil".to_string());
235 format!("(_ vec {})", vec)
236 }
237 Struct(fields) => {
238 let fields = fields
239 .iter()
240 .map(|(k, v)| format!("(|{}| {})", zencode::decode(symtab.to_str(*k)), v.to_string(symtab)))
241 .fold(
242 None,
243 |acc, kv| {
244 if let Some(prefix) = acc {
245 Some(format!("{} {}", prefix, kv))
246 } else {
247 Some(kv)
248 }
249 },
250 )
251 .unwrap();
252 format!("(_ struct {})", fields)
253 }
254 Ctor(ctor, v) => format!("(|{}| {})", zencode::decode(symtab.to_str(*ctor)), v.to_string(symtab)),
255 Ref(reg) => format!("(_ reg |{}|)", zencode::decode(symtab.to_str(*reg))),
256 Poison => "(_ poison)".to_string(),
257 }
258 }
259
260 pub fn plausible<N: std::fmt::Debug>(&self, ty: &Ty<N>, symtab: &Symtab) -> Result<(), String> {
262 match (self, ty) {
263 (Val::Symbolic(_), _) => Ok(()),
264 (Val::I64(_), Ty::I64) => Ok(()),
265 (Val::I128(_), Ty::I128) => Ok(()),
266 (Val::Bool(_), Ty::Bool) => Ok(()),
267 (Val::Bits(_), Ty::AnyBits) => Ok(()),
268 (Val::Bits(bv), Ty::Bits(n)) => {
269 if bv.len() == *n {
270 Ok(())
271 } else {
272 Err(format!("value {} doesn't appear to match type {:?}", self.to_string(symtab), ty))
273 }
274 }
275 (Val::String(_), Ty::String) => Ok(()),
276 (Val::Unit, Ty::Unit) => Ok(()),
277 (Val::Vector(_), Ty::Vector(_)) => Ok(()), (Val::List(_), Ty::List(_)) => Ok(()), (Val::Enum(_), Ty::Enum(_)) => Ok(()), (Val::Struct(_), Ty::Struct(_)) => Ok(()), (Val::Ctor(_, _), _) => Ok(()), (Val::Ref(_), _) => Ok(()), (Val::Poison, _) => Ok(()),
284 (_, _) => Err(format!("value {} doesn't appear to match type {:?}", self.to_string(symtab), ty)),
285 }
286 }
287}
288
289#[derive(Clone, Debug)]
291pub enum UVal<'ir, B> {
292 Uninit(&'ir Ty<Name>),
293 Init(Val<B>),
294}
295
296pub type Bindings<'ir, B> = HashMap<Name, UVal<'ir, B>>;
298
299pub enum Variable<'a, A> {
302 Declaration(&'a mut A),
303 Usage(&'a mut A),
304}
305
306pub struct Variables<'a, A> {
309 vec: Vec<Variable<'a, A>>,
310}
311
312impl<'a, A> Variables<'a, A> {
313 pub fn from_vec(vec: Vec<Variable<'a, A>>) -> Self {
314 Variables { vec }
315 }
316}
317
318impl<'a, A> Iterator for Variables<'a, A> {
319 type Item = Variable<'a, A>;
320
321 fn next(&mut self) -> Option<Self::Item> {
322 self.vec.pop()
323 }
324}
325
326#[derive(Clone, Debug, Serialize, Deserialize)]
327pub enum Exp<A> {
328 Id(A),
329 Ref(A),
330 Bool(bool),
331 Bits(B64),
332 String(String),
333 Unit,
334 I64(i64),
335 I128(i128),
336 Undefined(Ty<A>),
337 Struct(A, Vec<(A, Exp<A>)>),
338 Kind(A, Box<Exp<A>>),
339 Unwrap(A, Box<Exp<A>>),
340 Field(Box<Exp<A>>, A),
341 Call(Op, Vec<Exp<A>>),
342}
343
344impl<A: Hash + Eq + Clone> Exp<A> {
345 fn collect_ids(&self, ids: &mut HashSet<A>) {
346 use Exp::*;
347 match self {
348 Id(id) => {
349 ids.insert(id.clone());
350 }
351 Ref(_) | Bool(_) | Bits(_) | String(_) | Unit | I64(_) | I128(_) | Undefined(_) => (),
352 Kind(_, exp) | Unwrap(_, exp) | Field(exp, _) => exp.collect_ids(ids),
353 Call(_, exps) => exps.iter().for_each(|exp| exp.collect_ids(ids)),
354 Struct(_, fields) => fields.iter().for_each(|(_, exp)| exp.collect_ids(ids)),
355 }
356 }
357
358 pub(crate) fn collect_variables<'a, 'b>(&'a mut self, vars: &'b mut Vec<Variable<'a, A>>) {
359 use Exp::*;
360 match self {
361 Id(id) => vars.push(Variable::Usage(id)),
362 Ref(_) | Bool(_) | Bits(_) | String(_) | Unit | I64(_) | I128(_) | Undefined(_) => (),
363 Kind(_, exp) | Unwrap(_, exp) | Field(exp, _) => exp.collect_variables(vars),
364 Call(_, exps) => exps.iter_mut().for_each(|exp| exp.collect_variables(vars)),
365 Struct(_, fields) => fields.iter_mut().for_each(|(_, exp)| exp.collect_variables(vars)),
366 }
367 }
368
369 pub fn variables(&mut self) -> Variables<'_, A> {
370 let mut vec = Vec::new();
371 self.collect_variables(&mut vec);
372 Variables::from_vec(vec)
373 }
374}
375
376#[derive(Clone)]
377pub enum Instr<A, B> {
378 Decl(A, Ty<A>),
379 Init(A, Ty<A>, Exp<A>),
380 Jump(Exp<A>, usize, String),
381 Goto(usize),
382 Copy(Loc<A>, Exp<A>),
383 Monomorphize(A),
384 Call(Loc<A>, bool, A, Vec<Exp<A>>),
385 PrimopUnary(Loc<A>, Unary<B>, Exp<A>),
386 PrimopBinary(Loc<A>, Binary<B>, Exp<A>, Exp<A>),
387 PrimopVariadic(Loc<A>, Variadic<B>, Vec<Exp<A>>),
388 Failure,
389 Arbitrary,
390 End,
391}
392
393impl<A: fmt::Debug, B: fmt::Debug> fmt::Debug for Instr<A, B> {
394 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
395 use Instr::*;
396 match self {
397 Decl(id, ty) => write!(f, "{:?} : {:?}", id, ty),
398 Init(id, ty, exp) => write!(f, "{:?} : {:?} = {:?}", id, ty, exp),
399 Jump(exp, target, info) => write!(f, "jump {:?} to {:?} ` {:?}", exp, target, info),
400 Goto(target) => write!(f, "goto {:?}", target),
401 Copy(loc, exp) => write!(f, "{:?} = {:?}", loc, exp),
402 Monomorphize(id) => write!(f, "mono {:?}", id),
403 Call(loc, ext, id, args) => write!(f, "{:?} = {:?}<{:?}>({:?})", loc, id, ext, args),
404 Failure => write!(f, "failure"),
405 Arbitrary => write!(f, "arbitrary"),
406 End => write!(f, "end"),
407 PrimopUnary(loc, fptr, exp) => write!(f, "{:?} = {:p}({:?})", loc, fptr, exp),
408 PrimopBinary(loc, fptr, lhs, rhs) => write!(f, "{:?} = {:p}({:?}, {:?})", loc, fptr, lhs, rhs),
409 PrimopVariadic(loc, fptr, args) => write!(f, "{:?} = {:p}({:?})", loc, fptr, args),
410 }
411 }
412}
413
414pub fn append_instrs<A, B>(lhs: &mut Vec<Instr<A, B>>, rhs: &mut Vec<Instr<A, B>>) {
417 for instr in rhs.iter_mut() {
418 match instr {
419 Instr::Goto(label) => *label += lhs.len(),
420 Instr::Jump(_, label, _) => *label += lhs.len(),
421 _ => (),
422 }
423 }
424 lhs.append(rhs)
425}
426
427#[derive(Clone)]
428pub enum Def<A, B> {
429 Register(A, Ty<A>),
430 Let(Vec<(A, Ty<A>)>, Vec<Instr<A, B>>),
431 Enum(A, Vec<A>),
432 Struct(A, Vec<(A, Ty<A>)>),
433 Union(A, Vec<(A, Ty<A>)>),
434 Val(A, Vec<Ty<A>>, Ty<A>),
435 Extern(A, String, Vec<Ty<A>>, Ty<A>),
436 Fn(A, Vec<A>, Vec<Instr<A, B>>),
437}
438
439impl Name {
440 pub fn from_u32(id: u32) -> Self {
441 Name { id }
442 }
443}
444
445#[derive(Clone)]
448pub struct Symtab<'ir> {
449 symbols: Vec<&'ir str>,
450 table: HashMap<&'ir str, u32>,
451 next: u32,
452}
453
454pub const RETURN: Name = Name { id: 0 };
457
458pub const SAIL_ASSERT: Name = Name { id: 1 };
461
462pub const SAIL_ASSUME: Name = Name { id: 2 };
465
466pub const SAIL_EXIT: Name = Name { id: 3 };
469
470pub const CURRENT_EXCEPTION: Name = Name { id: 4 };
474
475pub const HAVE_EXCEPTION: Name = Name { id: 5 };
478
479pub const THROW_LOCATION: Name = Name { id: 6 };
482
483pub const INTERNAL_VECTOR_INIT: Name = Name { id: 7 };
485
486pub const INTERNAL_VECTOR_UPDATE: Name = Name { id: 8 };
488
489pub const BITVECTOR_UPDATE: Name = Name { id: 9 };
491
492pub const NULL: Name = Name { id: 10 };
494
495pub const ELF_ENTRY: Name = Name { id: 11 };
497
498pub const REG_DEREF: Name = Name { id: 12 };
501
502pub const SAIL_EXCEPTION: Name = Name { id: 13 };
504
505pub const TOP_LEVEL_LET: Name = Name { id: 14 };
507
508pub const BV_BIT_LEFT: Name = Name { id: 15 };
510
511pub const BV_BIT_RIGHT: Name = Name { id: 16 };
513
514pub const RESET_REGISTERS: Name = Name { id: 17 };
517
518static GENSYM: &str = "|GENSYM|";
519
520impl<'ir> Symtab<'ir> {
521 pub fn intern(&mut self, sym: &'ir str) -> Name {
522 match self.table.get(sym) {
523 None => {
524 let n = self.next;
525 self.symbols.push(sym);
526 self.table.insert(sym, n);
527 self.next += 1;
528 Name::from_u32(n)
529 }
530 Some(n) => Name::from_u32(*n),
531 }
532 }
533
534 pub fn gensym(&mut self) -> Name {
535 let n = self.next;
536 self.symbols.push(GENSYM);
537 self.table.insert(GENSYM, n);
538 self.next += 1;
539 Name::from_u32(n)
540 }
541
542 pub fn to_raw_table(&self) -> Vec<String> {
543 self.symbols.iter().map(|sym| (*sym).to_string()).collect()
544 }
545
546 pub fn from_raw_table(raw: &'ir [String]) -> Self {
547 let mut symtab =
548 Symtab { symbols: Vec::with_capacity(raw.len()), table: HashMap::with_capacity(raw.len()), next: 0 };
549 for sym in raw {
550 symtab.intern(sym);
551 }
552 symtab
553 }
554
555 pub fn to_str(&self, n: Name) -> &'ir str {
556 match self.symbols.get(n.id as usize) {
557 Some(s) => s,
558 None => "zUNKNOWN",
559 }
560 }
561
562 #[allow(clippy::new_without_default)]
563 pub fn new() -> Self {
564 let mut symtab = Symtab { symbols: Vec::new(), table: HashMap::new(), next: 0 };
565 symtab.intern("return");
566 symtab.intern("zsail_assert");
567 symtab.intern("zsail_assume");
568 symtab.intern("zsail_exit");
569 symtab.intern("current_exception");
570 symtab.intern("have_exception");
571 symtab.intern("throw_location");
572 symtab.intern("zinternal_vector_init");
573 symtab.intern("zinternal_vector_update");
574 symtab.intern("zupdate_fbits");
575 symtab.intern("NULL");
576 symtab.intern("elf_entry");
577 symtab.intern("reg_deref");
578 symtab.intern("zexception");
579 symtab.intern("|let|");
580 symtab.intern("ztuplez3z5bv_z5bit0");
581 symtab.intern("ztuplez3z5bv_z5bit1");
582 symtab.intern("reset_registers");
583 symtab
584 }
585
586 pub fn lookup(&self, sym: &str) -> Name {
587 Name::from_u32(*self.table.get(sym).unwrap_or_else(|| {
588 eprintln!("Could not find symbol: {}", sym);
589 &std::u32::MAX
590 }))
591 }
592
593 pub fn get(&self, sym: &str) -> Option<Name> {
594 self.table.get(sym).copied().map(Name::from_u32)
595 }
596
597 pub fn intern_ty(&mut self, ty: &'ir Ty<String>) -> Ty<Name> {
598 use Ty::*;
599 match ty {
600 I64 => I64,
601 I128 => I128,
602 AnyBits => AnyBits,
603 Bits(sz) => Bits(*sz),
604 Unit => Unit,
605 Bool => Bool,
606 Bit => Bit,
607 String => String,
608 Real => Real,
609 Enum(e) => Enum(self.lookup(e)),
610 Struct(s) => Struct(self.lookup(s)),
611 Union(u) => Union(self.lookup(u)),
612 Vector(ty) => Vector(Box::new(self.intern_ty(ty))),
613 FixedVector(sz, ty) => FixedVector(*sz, Box::new(self.intern_ty(ty))),
614 List(ty) => List(Box::new(self.intern_ty(ty))),
615 Ref(ty) => Ref(Box::new(self.intern_ty(ty))),
616 }
617 }
618
619 pub fn get_loc(&self, loc: &Loc<String>) -> Option<Loc<Name>> {
620 use Loc::*;
621 Some(match loc {
622 Id(v) => Id(self.get(v)?),
623 Field(loc, field) => Field(Box::new(self.get_loc(loc)?), self.get(field)?),
624 Addr(loc) => Addr(Box::new(self.get_loc(loc)?)),
625 })
626 }
627
628 pub fn intern_loc(&mut self, loc: &'ir Loc<String>) -> Loc<Name> {
629 use Loc::*;
630 match loc {
631 Id(v) => Id(self.lookup(v)),
632 Field(loc, field) => Field(Box::new(self.intern_loc(loc)), self.lookup(field)),
633 Addr(loc) => Addr(Box::new(self.intern_loc(loc))),
634 }
635 }
636
637 pub fn intern_exp(&mut self, exp: &'ir Exp<String>) -> Exp<Name> {
638 use Exp::*;
639 match exp {
640 Id(v) => Id(self.lookup(v)),
641 Ref(reg) => Ref(self.lookup(reg)),
642 Bool(b) => Bool(*b),
643 Bits(bv) => Bits(*bv),
644 String(s) => String(s.clone()),
645 Unit => Unit,
646 I64(i) => I64(*i),
647 I128(i) => I128(*i),
648 Undefined(ty) => Undefined(self.intern_ty(ty)),
649 Struct(s, fields) => Struct(
650 self.lookup(s),
651 fields.iter().map(|(field, exp)| (self.lookup(field), self.intern_exp(exp))).collect(),
652 ),
653 Kind(ctor, exp) => Kind(self.lookup(ctor), Box::new(self.intern_exp(exp))),
654 Unwrap(ctor, exp) => Unwrap(self.lookup(ctor), Box::new(self.intern_exp(exp))),
655 Field(exp, field) => Field(Box::new(self.intern_exp(exp)), self.lookup(field)),
656 Call(op, args) => Call(*op, args.iter().map(|exp| self.intern_exp(exp)).collect()),
657 }
658 }
659
660 pub fn intern_instr<B: BV>(&mut self, instr: &'ir Instr<String, B>) -> Instr<Name, B> {
661 use Instr::*;
662 match instr {
663 Decl(v, ty) => Decl(self.intern(v), self.intern_ty(ty)),
664 Init(v, ty, exp) => {
665 let exp = self.intern_exp(exp);
666 Init(self.intern(v), self.intern_ty(ty), exp)
667 }
668 Jump(exp, target, loc) => Jump(self.intern_exp(exp), *target, loc.clone()),
669 Goto(target) => Goto(*target),
670 Copy(loc, exp) => Copy(self.intern_loc(loc), self.intern_exp(exp)),
671 Monomorphize(id) => Monomorphize(self.lookup(id)),
672 Call(loc, ext, f, args) => {
673 let loc = self.intern_loc(loc);
674 let args = args.iter().map(|exp| self.intern_exp(exp)).collect();
675 Call(loc, *ext, self.lookup(f), args)
676 }
677 Failure => Failure,
678 Arbitrary => Arbitrary,
679 End => End,
680 PrimopUnary(_, _, _) => unreachable!("PrimopUnary in intern_instr"),
683 PrimopBinary(_, _, _, _) => unreachable!("PrimopBinary in intern_instr"),
684 PrimopVariadic(_, _, _) => unreachable!("PrimopVariadic in intern_instr"),
685 }
686 }
687
688 pub fn intern_def<B: BV>(&mut self, def: &'ir Def<String, B>) -> Def<Name, B> {
689 use Def::*;
690 match def {
691 Register(reg, ty) => Register(self.intern(reg), self.intern_ty(ty)),
692 Let(bindings, setup) => {
693 let bindings = bindings.iter().map(|(v, ty)| (self.intern(v), self.intern_ty(ty))).collect();
694 let setup = setup.iter().map(|instr| self.intern_instr(instr)).collect();
695 Let(bindings, setup)
696 }
697 Enum(e, ctors) => Enum(self.intern(e), ctors.iter().map(|ctor| self.intern(ctor)).collect()),
698 Struct(s, fields) => {
699 let fields = fields.iter().map(|(field, ty)| (self.intern(field), self.intern_ty(ty))).collect();
700 Struct(self.intern(s), fields)
701 }
702 Union(u, ctors) => {
703 let ctors = ctors.iter().map(|(ctor, ty)| (self.intern(ctor), self.intern_ty(ty))).collect();
704 Union(self.intern(u), ctors)
705 }
706 Val(f, args, ret) => {
707 Val(self.intern(f), args.iter().map(|ty| self.intern_ty(ty)).collect(), self.intern_ty(ret))
708 }
709 Extern(f, ext, args, ret) => Extern(
710 self.intern(f),
711 ext.clone(),
712 args.iter().map(|ty| self.intern_ty(ty)).collect(),
713 self.intern_ty(ret),
714 ),
715 Fn(f, args, body) => {
716 let args = args.iter().map(|arg| self.intern(arg)).collect();
717 let body = body.iter().map(|instr| self.intern_instr(instr)).collect();
718 Fn(self.lookup(f), args, body)
719 }
720 }
721 }
722
723 pub fn intern_defs<B: BV>(&mut self, defs: &'ir [Def<String, B>]) -> Vec<Def<Name, B>> {
724 defs.iter().map(|def| self.intern_def(def)).collect()
725 }
726}
727
728type FnDecl<'ir, B> = (Vec<(Name, &'ir Ty<Name>)>, Ty<Name>, &'ir [Instr<Name, B>]);
732
733pub type Reset<B> = Arc<dyn 'static + Send + Sync + Fn(&Memory<B>, &mut Solver<B>) -> Result<Val<B>, ExecError>>;
749
750pub struct SharedState<'ir, B> {
754 pub functions: HashMap<Name, FnDecl<'ir, B>>,
756 pub symtab: Symtab<'ir>,
758 pub structs: HashMap<Name, HashMap<Name, Ty<Name>>>,
761 pub enums: HashMap<Name, HashSet<Name>>,
764 pub enum_members: HashMap<Name, (usize, usize)>,
768 pub union_ctors: HashSet<Name>,
770 pub probes: HashSet<Name>,
772 pub reset_registers: HashMap<Loc<Name>, Reset<B>>,
775}
776
777impl<'ir, B: BV> SharedState<'ir, B> {
778 pub fn new(
779 symtab: Symtab<'ir>,
780 defs: &'ir [Def<Name, B>],
781 probes: HashSet<Name>,
782 reset_registers: HashMap<Loc<Name>, Reset<B>>,
783 ) -> Self {
784 let mut vals = HashMap::new();
785 let mut functions: HashMap<Name, FnDecl<'ir, B>> = HashMap::new();
786 let mut structs: HashMap<Name, HashMap<Name, Ty<Name>>> = HashMap::new();
787 let mut enums: HashMap<Name, HashSet<Name>> = HashMap::new();
788 let mut enum_members: HashMap<Name, (usize, usize)> = HashMap::new();
789 let mut union_ctors: HashSet<Name> = HashSet::new();
790
791 for def in defs {
792 match def {
793 Def::Val(f, arg_tys, ret_ty) => {
794 vals.insert(f, (arg_tys, ret_ty));
795 }
796
797 Def::Fn(f, args, body) => match vals.get(f) {
798 None => panic!("Found fn without a val when creating the global state!"),
799 Some((arg_tys, ret_ty)) => {
800 assert!(arg_tys.len() == args.len());
801 let args = args.iter().zip(arg_tys.iter()).map(|(id, ty)| (*id, ty)).collect();
802 functions.insert(*f, (args, (*ret_ty).clone(), body));
803 }
804 },
805
806 Def::Struct(name, fields) => {
807 let fields: HashMap<_, _> = fields.clone().into_iter().collect();
808 structs.insert(*name, fields);
809 }
810
811 Def::Enum(name, members) => {
812 for (i, member) in members.iter().enumerate() {
813 enum_members.insert(*member, (i, members.len()));
814 }
815 let members: HashSet<_> = members.clone().into_iter().collect();
816 enums.insert(*name, members);
817 }
818
819 Def::Union(_, ctors) => {
820 for (ctor, _) in ctors {
821 union_ctors.insert(*ctor);
822 }
823 }
824
825 _ => (),
826 }
827 }
828
829 SharedState { functions, symtab, structs, enums, enum_members, union_ctors, probes, reset_registers }
830 }
831
832 pub fn enum_member_from_str(&self, member: &str) -> Option<usize> {
833 let member = self.symtab.get(&zencode::encode(member))?;
834 self.enum_members.get(&member).map(|(pos, _)| *pos)
835 }
836
837 pub fn enum_member(&self, member: Name) -> Option<usize> {
838 self.enum_members.get(&member).map(|(pos, _)| *pos)
839 }
840}
841
842fn insert_instr_primops<B: BV>(
843 instr: Instr<Name, B>,
844 externs: &HashMap<Name, String>,
845 primops: &Primops<B>,
846) -> Instr<Name, B> {
847 match &instr {
848 Instr::Call(loc, _, f, args) => match externs.get(&f) {
849 Some(name) => {
850 if let Some(unop) = primops.unary.get(name) {
851 assert!(args.len() == 1);
852 Instr::PrimopUnary(loc.clone(), *unop, args[0].clone())
853 } else if let Some(binop) = primops.binary.get(name) {
854 assert!(args.len() == 2);
855 Instr::PrimopBinary(loc.clone(), *binop, args[0].clone(), args[1].clone())
856 } else if let Some(varop) = primops.variadic.get(name) {
857 Instr::PrimopVariadic(loc.clone(), *varop, args.clone())
858 } else if name == "reg_deref" {
859 Instr::Call(loc.clone(), false, REG_DEREF, args.clone())
860 } else if name == "reset_registers" {
861 Instr::Call(loc.clone(), false, RESET_REGISTERS, args.clone())
862 } else {
863 eprintln!("No primop {} ({:?})", name, f);
867 Instr::Call(loc.clone(), false, *f, args.clone())
868 }
869 }
870 None => instr,
871 },
872 _ => instr,
873 }
874}
875
876pub enum AssertionMode {
883 Pessimistic,
884 Optimistic,
885}
886
887pub(crate) fn insert_primops<B: BV>(defs: &mut [Def<Name, B>], mode: AssertionMode) {
889 let mut externs: HashMap<Name, String> = HashMap::new();
890 for def in defs.iter() {
891 if let Def::Extern(f, ext, _, _) = def {
892 externs.insert(*f, ext.to_string());
893 }
894 }
895
896 match mode {
897 AssertionMode::Optimistic => externs.insert(SAIL_ASSERT, "optimistic_assert".to_string()),
898 AssertionMode::Pessimistic => externs.insert(SAIL_ASSERT, "pessimistic_assert".to_string()),
899 };
900 externs.insert(SAIL_ASSUME, "assume".to_string());
901 externs.insert(BITVECTOR_UPDATE, "bitvector_update".to_string());
902
903 let primops = Primops::default();
904
905 for def in defs.iter_mut() {
906 match def {
907 Def::Fn(f, args, body) => {
908 *def = Def::Fn(
909 *f,
910 args.to_vec(),
911 body.to_vec().into_iter().map(|instr| insert_instr_primops(instr, &externs, &primops)).collect(),
912 )
913 }
914 Def::Let(bindings, setup) => {
915 *def = Def::Let(
916 bindings.clone(),
917 setup.to_vec().into_iter().map(|instr| insert_instr_primops(instr, &externs, &primops)).collect(),
918 )
919 }
920 _ => (),
921 }
922 }
923}
924
925#[derive(Debug)]
932pub enum LabeledInstr<B> {
933 Labeled(usize, Instr<Name, B>),
934 Unlabeled(Instr<Name, B>),
935}
936
937impl<B: BV> LabeledInstr<B> {
938 fn strip(self) -> Instr<Name, B> {
939 use LabeledInstr::*;
940 match self {
941 Labeled(_, instr) => instr,
942 Unlabeled(instr) => instr,
943 }
944 }
945
946 fn strip_ref(&self) -> &Instr<Name, B> {
947 use LabeledInstr::*;
948 match self {
949 Labeled(_, instr) => instr,
950 Unlabeled(instr) => instr,
951 }
952 }
953
954 fn label(&self) -> Option<usize> {
955 match self {
956 LabeledInstr::Labeled(l, _) => Some(*l),
957 LabeledInstr::Unlabeled(_) => None,
958 }
959 }
960
961 fn is_labeled(&self) -> bool {
962 matches!(self, LabeledInstr::Labeled(_, _))
963 }
964
965 fn is_unlabeled(&self) -> bool {
966 !self.is_labeled()
967 }
968}
969
970pub fn label_instrs<B: BV>(mut instrs: Vec<Instr<Name, B>>) -> Vec<LabeledInstr<B>> {
976 use LabeledInstr::*;
977 instrs.drain(..).enumerate().map(|(i, instr)| Labeled(i, instr)).collect()
978}
979
980pub fn prune_labels<B: BV>(mut instrs: Vec<LabeledInstr<B>>) -> Vec<LabeledInstr<B>> {
982 use LabeledInstr::*;
983 let mut targets = HashSet::new();
984
985 for instr in &instrs {
986 match instr.strip_ref() {
987 Instr::Goto(target) | Instr::Jump(_, target, _) => {
988 targets.insert(*target);
989 }
990 _ => (),
991 }
992 }
993
994 instrs
995 .drain(..)
996 .map(|instr| match instr {
997 Labeled(l, instr) if targets.contains(&l) => Labeled(l, instr),
998 instr => Unlabeled(instr.strip()),
999 })
1000 .collect()
1001}
1002
1003pub fn unlabel_instrs<B: BV>(mut instrs: Vec<LabeledInstr<B>>) -> Vec<Instr<Name, B>> {
1006 use LabeledInstr::*;
1007
1008 let mut jump_table: HashMap<usize, usize> = HashMap::new();
1009
1010 for (i, instr) in instrs.iter().enumerate() {
1011 match instr {
1012 Labeled(label, _) => {
1013 jump_table.insert(*label, i);
1014 }
1015 Unlabeled(_) => (),
1016 }
1017 }
1018
1019 instrs
1020 .drain(..)
1021 .map(|instr| match instr.strip() {
1022 Instr::Jump(cond, target, loc) => {
1023 let new_target = jump_table.get(&target).unwrap();
1024 Instr::Jump(cond, *new_target, loc)
1025 }
1026
1027 Instr::Goto(target) => {
1028 let new_target = jump_table.get(&target).unwrap();
1029 Instr::Goto(*new_target)
1030 }
1031
1032 instr => instr,
1033 })
1034 .collect()
1035}
1036
1037fn insert_monomorphize_instrs<B: BV>(instrs: Vec<Instr<Name, B>>, mono_fns: &HashSet<Name>) -> Vec<Instr<Name, B>> {
1038 use LabeledInstr::*;
1039 let mut new_instrs = Vec::new();
1040
1041 for instr in label_instrs(instrs) {
1042 match instr {
1043 Labeled(label, Instr::Call(loc, ext, f, args)) if mono_fns.contains(&f) => {
1044 let mut ids = HashSet::new();
1045 args.iter().for_each(|exp| exp.collect_ids(&mut ids));
1046
1047 if ids.is_empty() {
1048 new_instrs.push(Labeled(label, Instr::Call(loc, ext, f, args)))
1049 } else {
1050 for (i, id) in ids.iter().enumerate() {
1051 if i == 0 {
1052 new_instrs.push(Labeled(label, Instr::Monomorphize(*id)))
1053 } else {
1054 new_instrs.push(Unlabeled(Instr::Monomorphize(*id)))
1055 }
1056 }
1057 new_instrs.push(Unlabeled(Instr::Call(loc, ext, f, args)))
1058 }
1059 }
1060
1061 _ => new_instrs.push(instr),
1062 }
1063 }
1064
1065 unlabel_instrs(new_instrs)
1066}
1067
1068fn has_mono_fn<B: BV>(instrs: &[Instr<Name, B>], mono_fns: &HashSet<Name>) -> bool {
1069 for instr in instrs {
1070 match instr {
1071 Instr::Call(_, _, f, _) if mono_fns.contains(&f) => return true,
1072 _ => (),
1073 }
1074 }
1075 false
1076}
1077
1078pub(crate) fn insert_monomorphize<B: BV>(defs: &mut [Def<Name, B>]) {
1079 let mut mono_fns = HashSet::new();
1080 for def in defs.iter() {
1081 match def {
1082 Def::Extern(f, ext, _, _) if ext == "monomorphize" => {
1083 mono_fns.insert(*f);
1084 }
1085 _ => (),
1086 }
1087 }
1088
1089 for def in defs.iter_mut() {
1090 match def {
1091 Def::Fn(f, args, body) if has_mono_fn(body, &mono_fns) => {
1092 *def = Def::Fn(*f, args.to_vec(), insert_monomorphize_instrs(body.to_vec(), &mono_fns))
1093 }
1094 _ => (),
1095 }
1096 }
1097}