1use cranelift_isle::ast::{self, Signature};
2use std::collections::HashMap;
3use veri_ir::annotation_ir;
4
5use cranelift_isle::ast::{Def, Ident, Model, ModelType, SpecExpr, SpecOp};
6use cranelift_isle::lexer::Pos;
7use cranelift_isle::sema::{TermEnv, TermId, TypeEnv, TypeId};
8use veri_ir::annotation_ir::Width;
9use veri_ir::annotation_ir::{BoundVar, Const, Expr, TermAnnotation, TermSignature, Type};
10use veri_ir::TermSignature as TermTypeSignature;
11
12static RESULT: &str = "result";
13
14#[derive(Clone, Debug)]
15pub struct ParsingEnv<'a> {
16 pub typeenv: &'a TypeEnv,
17 pub enums: HashMap<String, Expr>,
18}
19
20#[derive(Clone, Debug)]
21pub struct AnnotationEnv {
22 pub annotation_map: HashMap<TermId, TermAnnotation>,
23
24 pub instantiations_map: HashMap<TermId, Vec<TermTypeSignature>>,
26
27 pub model_map: HashMap<TypeId, annotation_ir::Type>,
30}
31
32impl AnnotationEnv {
33 pub fn get_annotation_for_term(&self, term_id: &TermId) -> Option<TermAnnotation> {
34 if self.annotation_map.contains_key(term_id) {
35 return Some(self.annotation_map[term_id].clone());
36 }
37 None
38 }
39
40 pub fn get_term_signatures_by_name(
41 &self,
42 termenv: &TermEnv,
43 typeenv: &TypeEnv,
44 ) -> HashMap<String, Vec<TermTypeSignature>> {
45 let mut term_signatures_by_name = HashMap::new();
46 for (term_id, term_sigs) in &self.instantiations_map {
47 let sym = termenv.terms[term_id.index()].name;
48 let name = typeenv.syms[sym.index()].clone();
49 term_signatures_by_name.insert(name, term_sigs.clone());
50 }
51 term_signatures_by_name
52 }
53}
54
55pub fn spec_to_annotation_bound_var(i: &Ident) -> BoundVar {
56 BoundVar {
57 name: i.0.clone(),
58 ty: None,
59 }
60}
61
62fn spec_to_usize(s: &SpecExpr) -> Option<usize> {
63 match s {
64 SpecExpr::ConstInt { val, pos: _ } => Some(*val as usize),
65 _ => None,
66 }
67}
68
69fn spec_op_to_expr(s: &SpecOp, args: &[SpecExpr], pos: &Pos, env: &ParsingEnv) -> Expr {
70 fn unop<F: Fn(Box<Expr>) -> Expr>(
71 u: F,
72 args: &[SpecExpr],
73 pos: &Pos,
74 env: &ParsingEnv,
75 ) -> Expr {
76 assert_eq!(
77 args.len(),
78 1,
79 "Unexpected number of args for unary operator {:?}",
80 pos
81 );
82 u(Box::new(spec_to_expr(&args[0], env)))
83 }
84 fn binop<F: Fn(Box<Expr>, Box<Expr>) -> Expr>(
85 b: F,
86 args: &[SpecExpr],
87 _pos: &Pos,
88 env: &ParsingEnv,
89 ) -> Expr {
90 assert_eq!(
91 args.len(),
92 2,
93 "Unexpected number of args for binary operator {:?}",
94 args
95 );
96 b(
97 Box::new(spec_to_expr(&args[0], env)),
98 Box::new(spec_to_expr(&args[1], env)),
99 )
100 }
101
102 fn variadic_binop<F: Fn(Box<Expr>, Box<Expr>) -> Expr>(
103 b: F,
104 args: &[SpecExpr],
105 pos: &Pos,
106 env: &ParsingEnv,
107 ) -> Expr {
108 assert!(
109 !args.is_empty(),
110 "Unexpected number of args for variadic binary operator {:?}",
111 pos
112 );
113 let mut expr_args: Vec<Expr> = args.iter().map(|a| spec_to_expr(a, env)).collect();
114 let last = expr_args.remove(expr_args.len() - 1);
115
116 expr_args
118 .iter()
119 .rev()
120 .fold(last, |acc, a| b(Box::new(a.clone()), Box::new(acc)))
121 }
122
123 match s {
124 SpecOp::Not => unop(Expr::Not, args, pos, env),
126 SpecOp::BVNot => unop(Expr::BVNot, args, pos, env),
127 SpecOp::BVNeg => unop(Expr::BVNeg, args, pos, env),
128 SpecOp::Rev => unop(Expr::Rev, args, pos, env),
129 SpecOp::Clz => unop(Expr::CLZ, args, pos, env),
130 SpecOp::Cls => unop(Expr::CLS, args, pos, env),
131 SpecOp::Popcnt => unop(Expr::BVPopcnt, args, pos, env),
132 SpecOp::BV2Int => unop(Expr::BVToInt, args, pos, env),
133
134 SpecOp::And => variadic_binop(Expr::And, args, pos, env),
136 SpecOp::Or => variadic_binop(Expr::Or, args, pos, env),
137
138 SpecOp::Eq => binop(Expr::Eq, args, pos, env),
140 SpecOp::Lt => binop(Expr::Lt, args, pos, env),
141 SpecOp::Lte => binop(Expr::Lte, args, pos, env),
142 SpecOp::Gt => binop(|x, y| Expr::Lt(y, x), args, pos, env),
143 SpecOp::Gte => binop(|x, y| Expr::Lte(y, x), args, pos, env),
144 SpecOp::Imp => binop(Expr::Imp, args, pos, env),
145 SpecOp::BVAnd => binop(Expr::BVAnd, args, pos, env),
146 SpecOp::BVOr => binop(Expr::BVOr, args, pos, env),
147 SpecOp::BVXor => binop(Expr::BVXor, args, pos, env),
148 SpecOp::BVAdd => binop(Expr::BVAdd, args, pos, env),
149 SpecOp::BVSub => binop(Expr::BVSub, args, pos, env),
150 SpecOp::BVMul => binop(Expr::BVMul, args, pos, env),
151 SpecOp::BVUdiv => binop(Expr::BVUDiv, args, pos, env),
152 SpecOp::BVUrem => binop(Expr::BVUrem, args, pos, env),
153 SpecOp::BVSdiv => binop(Expr::BVSDiv, args, pos, env),
154 SpecOp::BVSrem => binop(Expr::BVSrem, args, pos, env),
155 SpecOp::BVShl => binop(Expr::BVShl, args, pos, env),
156 SpecOp::BVLshr => binop(Expr::BVShr, args, pos, env),
157 SpecOp::BVAshr => binop(Expr::BVAShr, args, pos, env),
158 SpecOp::BVSaddo => binop(Expr::BVSaddo, args, pos, env),
159 SpecOp::BVUle => binop(Expr::BVUlte, args, pos, env),
160 SpecOp::BVUlt => binop(Expr::BVUlt, args, pos, env),
161 SpecOp::BVUgt => binop(Expr::BVUgt, args, pos, env),
162 SpecOp::BVUge => binop(Expr::BVUgte, args, pos, env),
163 SpecOp::BVSlt => binop(Expr::BVSlt, args, pos, env),
164 SpecOp::BVSle => binop(Expr::BVSlte, args, pos, env),
165 SpecOp::BVSgt => binop(Expr::BVSgt, args, pos, env),
166 SpecOp::BVSge => binop(Expr::BVSgte, args, pos, env),
167 SpecOp::Rotr => binop(Expr::BVRotr, args, pos, env),
168 SpecOp::Rotl => binop(Expr::BVRotl, args, pos, env),
169 SpecOp::ZeroExt => match spec_to_usize(&args[0]) {
170 Some(i) => Expr::BVZeroExtTo(
171 Box::new(Width::Const(i)),
172 Box::new(spec_to_expr(&args[1], env)),
173 ),
174 None => binop(Expr::BVZeroExtToVarWidth, args, pos, env),
175 },
176 SpecOp::SignExt => match spec_to_usize(&args[0]) {
177 Some(i) => Expr::BVSignExtTo(
178 Box::new(Width::Const(i)),
179 Box::new(spec_to_expr(&args[1], env)),
180 ),
181 None => binop(Expr::BVSignExtToVarWidth, args, pos, env),
182 },
183 SpecOp::ConvTo => binop(Expr::BVConvTo, args, pos, env),
184 SpecOp::Concat => {
185 let cases: Vec<Expr> = args.iter().map(|a| spec_to_expr(a, env)).collect();
186 Expr::BVConcat(cases)
187 }
188 SpecOp::Extract => {
189 assert_eq!(
190 args.len(),
191 3,
192 "Unexpected number of args for extract operator {:?}",
193 pos
194 );
195 Expr::BVExtract(
196 spec_to_usize(&args[0]).unwrap(),
197 spec_to_usize(&args[1]).unwrap(),
198 Box::new(spec_to_expr(&args[2], env)),
199 )
200 }
201 SpecOp::Int2BV => {
202 assert_eq!(
203 args.len(),
204 2,
205 "Unexpected number of args for Int2BV operator {:?}",
206 pos
207 );
208 Expr::BVIntToBv(
209 spec_to_usize(&args[0]).unwrap(),
210 Box::new(spec_to_expr(&args[1], env)),
211 )
212 }
213 SpecOp::Subs => {
214 assert_eq!(
215 args.len(),
216 3,
217 "Unexpected number of args for subs operator {:?}",
218 pos
219 );
220 Expr::BVSubs(
221 Box::new(spec_to_expr(&args[0], env)),
222 Box::new(spec_to_expr(&args[1], env)),
223 Box::new(spec_to_expr(&args[2], env)),
224 )
225 }
226 SpecOp::WidthOf => unop(Expr::WidthOf, args, pos, env),
227 SpecOp::If => {
228 assert_eq!(
229 args.len(),
230 3,
231 "Unexpected number of args for extract operator {:?}",
232 pos
233 );
234 Expr::Conditional(
235 Box::new(spec_to_expr(&args[0], env)),
236 Box::new(spec_to_expr(&args[1], env)),
237 Box::new(spec_to_expr(&args[2], env)),
238 )
239 }
240 SpecOp::Switch => {
241 assert!(
242 args.len() > 1,
243 "Unexpected number of args for switch operator {:?}",
244 pos
245 );
246 let swith_on = spec_to_expr(&args[0], env);
247 let arms: Vec<(Expr, Expr)> = args[1..]
248 .iter()
249 .map(|a| match a {
250 SpecExpr::Pair { l, r } => {
251 let l_expr = spec_to_expr(l, env);
252 let r_expr = spec_to_expr(r, env);
253 (l_expr, r_expr)
254 }
255 _ => unreachable!(),
256 })
257 .collect();
258 Expr::Switch(Box::new(swith_on), arms)
259 }
260 SpecOp::LoadEffect => {
261 assert_eq!(
262 args.len(),
263 3,
264 "Unexpected number of args for load operator {:?}",
265 pos
266 );
267 Expr::LoadEffect(
268 Box::new(spec_to_expr(&args[0], env)),
269 Box::new(spec_to_expr(&args[1], env)),
270 Box::new(spec_to_expr(&args[2], env)),
271 )
272 }
273 SpecOp::StoreEffect => {
274 assert_eq!(
275 args.len(),
276 4,
277 "Unexpected number of args for store operator {:?}",
278 pos
279 );
280 Expr::StoreEffect(
281 Box::new(spec_to_expr(&args[0], env)),
282 Box::new(spec_to_expr(&args[1], env)),
283 Box::new(spec_to_expr(&args[2], env)),
284 Box::new(spec_to_expr(&args[3], env)),
285 )
286 }
287 }
288}
289
290fn spec_to_expr(s: &SpecExpr, env: &ParsingEnv) -> Expr {
291 match s {
292 SpecExpr::ConstUnit { pos: _ } => Expr::Const(Const {
293 ty: Type::Unit,
294 value: 0,
295 width: 0,
296 }),
297 SpecExpr::ConstInt { val, pos: _ } => Expr::Const(Const {
298 ty: Type::Int,
299 value: *val,
300 width: 0,
301 }),
302 SpecExpr::ConstBitVec { val, width, pos: _ } => Expr::Const(Const {
303 ty: Type::BitVectorWithWidth(*width as usize),
304 value: *val,
305 width: (*width as usize),
306 }),
307 SpecExpr::ConstBool { val, pos: _ } => Expr::Const(Const {
308 ty: Type::Bool,
309 value: *val as i128,
310 width: 0,
311 }),
312 SpecExpr::Var { var, pos: _ } => Expr::Var(var.0.clone()),
313 SpecExpr::Op { op, args, pos } => spec_op_to_expr(op, args, pos, env),
314 SpecExpr::Pair { l, r } => {
315 unreachable!(
316 "pairs currently only parsed as part of Switch statements, {:?} {:?}",
317 l, r
318 )
319 }
320 SpecExpr::Enum { name } => {
321 if let Some(e) = env.enums.get(&name.0) {
322 e.clone()
323 } else {
324 panic!("Can't find model for enum {}", name.0);
325 }
326 }
327 }
328}
329
330fn model_type_to_type(model_type: &ModelType) -> veri_ir::Type {
331 match model_type {
332 ModelType::Int => veri_ir::Type::Int,
333 ModelType::Unit => veri_ir::Type::Unit,
334 ModelType::Bool => veri_ir::Type::Bool,
335 ModelType::BitVec(size) => veri_ir::Type::BitVector(*size),
336 }
337}
338
339fn signature_to_term_type_signature(sig: &Signature) -> TermTypeSignature {
340 TermTypeSignature {
341 args: sig.args.iter().map(model_type_to_type).collect(),
342 ret: model_type_to_type(&sig.ret),
343 canonical_type: Some(model_type_to_type(&sig.canonical)),
344 }
345}
346
347pub fn parse_annotations(defs: &[Def], termenv: &TermEnv, typeenv: &TypeEnv) -> AnnotationEnv {
348 let mut annotation_map = HashMap::new();
349 let mut model_map = HashMap::new();
350
351 let mut env = ParsingEnv {
352 typeenv,
353 enums: HashMap::new(),
354 };
355
356 for def in defs {
358 if let &ast::Def::Model(Model { ref name, ref val }) = def {
359 match val {
360 ast::ModelValue::TypeValue(model_type) => {
361 let type_id = typeenv.get_type_by_name(name).unwrap();
362 let ir_type = match model_type {
363 ModelType::Int => annotation_ir::Type::Int,
364 ModelType::Unit => annotation_ir::Type::Unit,
365 ModelType::Bool => annotation_ir::Type::Bool,
366 ModelType::BitVec(None) => annotation_ir::Type::BitVector,
367 ModelType::BitVec(Some(size)) => {
368 annotation_ir::Type::BitVectorWithWidth(*size)
369 }
370 };
371 model_map.insert(type_id, ir_type);
372 }
373 ast::ModelValue::EnumValues(vals) => {
374 for (v, e) in vals {
375 let ident = ast::Ident(format!("{}.{}", name.0, v.0), v.1);
376 let term_id = termenv.get_term_by_name(typeenv, &ident).unwrap();
377 let val = spec_to_expr(e, &env);
378 let ty = match val {
379 Expr::Const(Const { ref ty, .. }) => ty,
380 _ => unreachable!(),
381 };
382 env.enums.insert(ident.0.clone(), val.clone());
383 let result = BoundVar {
384 name: RESULT.to_string(),
385 ty: Some(ty.clone()),
386 };
387 let sig = TermSignature {
388 args: vec![],
389 ret: result,
390 };
391 let annotation = TermAnnotation {
392 sig,
393 assumptions: vec![Box::new(Expr::Eq(
394 Box::new(Expr::Var(RESULT.to_string())),
395 Box::new(val),
396 ))],
397 assertions: vec![],
398 };
399 annotation_map.insert(term_id, annotation);
400 }
401 }
402 }
403 }
404 }
405
406 for def in defs {
408 if let ast::Def::Spec(spec) = def {
409 let termname = spec.term.0.clone();
410 let term_id = termenv
411 .get_term_by_name(typeenv, &spec.term)
412 .unwrap_or_else(|| panic!("Spec provided for unknown decl {termname}"));
413 assert!(
414 !annotation_map.contains_key(&term_id),
415 "duplicate spec for {}",
416 termname
417 );
418 let sig = TermSignature {
419 args: spec.args.iter().map(spec_to_annotation_bound_var).collect(),
420 ret: BoundVar {
421 name: RESULT.to_string(),
422 ty: None,
423 },
424 };
425
426 let mut assumptions = vec![];
427 let mut assertions = vec![];
428 for a in &spec.provides {
429 assumptions.push(Box::new(spec_to_expr(a, &env)));
430 }
431
432 for a in &spec.requires {
433 assertions.push(Box::new(spec_to_expr(a, &env)));
434 }
435
436 let annotation = TermAnnotation {
437 sig,
438 assumptions,
439 assertions,
440 };
441 annotation_map.insert(term_id, annotation);
442 }
443 }
444
445 let mut forms_map = HashMap::new();
447 for def in defs {
448 if let ast::Def::Form(form) = def {
449 let term_type_signatures: Vec<_> = form
450 .signatures
451 .iter()
452 .map(signature_to_term_type_signature)
453 .collect();
454 forms_map.insert(form.name.0.clone(), term_type_signatures);
455 }
456 }
457
458 let mut instantiations_map = HashMap::new();
459 for def in defs {
460 if let ast::Def::Instantiation(inst) = def {
461 let term_id = termenv.get_term_by_name(typeenv, &inst.term).unwrap();
462 let sigs = match &inst.form {
463 Some(form) => forms_map[&form.0].clone(),
464 None => inst
465 .signatures
466 .iter()
467 .map(signature_to_term_type_signature)
468 .collect(),
469 };
470 instantiations_map.insert(term_id, sigs);
471 }
472 }
473
474 AnnotationEnv {
475 annotation_map,
476 instantiations_map,
477 model_map,
478 }
479}