Path: blob/main/cranelift/isle/veri/veri_engine/src/annotations.rs
1693 views
use cranelift_isle::ast::{self, Signature};1use std::collections::HashMap;2use veri_ir::annotation_ir;34use cranelift_isle::ast::{Def, Ident, Model, ModelType, SpecExpr, SpecOp};5use cranelift_isle::lexer::Pos;6use cranelift_isle::sema::{TermEnv, TermId, TypeEnv, TypeId};7use veri_ir::annotation_ir::Width;8use veri_ir::annotation_ir::{BoundVar, Const, Expr, TermAnnotation, TermSignature, Type};9use veri_ir::TermSignature as TermTypeSignature;1011static RESULT: &str = "result";1213#[derive(Clone, Debug)]14pub struct ParsingEnv<'a> {15pub typeenv: &'a TypeEnv,16pub enums: HashMap<String, Expr>,17}1819#[derive(Clone, Debug)]20pub struct AnnotationEnv {21pub annotation_map: HashMap<TermId, TermAnnotation>,2223// Mapping from ISLE term to its signature instantiations.24pub instantiations_map: HashMap<TermId, Vec<TermTypeSignature>>,2526// Mapping from ISLE type to its model (the annotation used to represent27// it).28pub model_map: HashMap<TypeId, annotation_ir::Type>,29}3031impl AnnotationEnv {32pub fn get_annotation_for_term(&self, term_id: &TermId) -> Option<TermAnnotation> {33if self.annotation_map.contains_key(term_id) {34return Some(self.annotation_map[term_id].clone());35}36None37}3839pub fn get_term_signatures_by_name(40&self,41termenv: &TermEnv,42typeenv: &TypeEnv,43) -> HashMap<String, Vec<TermTypeSignature>> {44let mut term_signatures_by_name = HashMap::new();45for (term_id, term_sigs) in &self.instantiations_map {46let sym = termenv.terms[term_id.index()].name;47let name = typeenv.syms[sym.index()].clone();48term_signatures_by_name.insert(name, term_sigs.clone());49}50term_signatures_by_name51}52}5354pub fn spec_to_annotation_bound_var(i: &Ident) -> BoundVar {55BoundVar {56name: i.0.clone(),57ty: None,58}59}6061fn spec_to_usize(s: &SpecExpr) -> Option<usize> {62match s {63SpecExpr::ConstInt { val, pos: _ } => Some(*val as usize),64_ => None,65}66}6768fn spec_op_to_expr(s: &SpecOp, args: &[SpecExpr], pos: &Pos, env: &ParsingEnv) -> Expr {69fn unop<F: Fn(Box<Expr>) -> Expr>(70u: F,71args: &[SpecExpr],72pos: &Pos,73env: &ParsingEnv,74) -> Expr {75assert_eq!(76args.len(),771,78"Unexpected number of args for unary operator {pos:?}",79);80u(Box::new(spec_to_expr(&args[0], env)))81}82fn binop<F: Fn(Box<Expr>, Box<Expr>) -> Expr>(83b: F,84args: &[SpecExpr],85_pos: &Pos,86env: &ParsingEnv,87) -> Expr {88assert_eq!(89args.len(),902,91"Unexpected number of args for binary operator {args:?}",92);93b(94Box::new(spec_to_expr(&args[0], env)),95Box::new(spec_to_expr(&args[1], env)),96)97}9899fn variadic_binop<F: Fn(Box<Expr>, Box<Expr>) -> Expr>(100b: F,101args: &[SpecExpr],102pos: &Pos,103env: &ParsingEnv,104) -> Expr {105assert!(106!args.is_empty(),107"Unexpected number of args for variadic binary operator {pos:?}",108);109let mut expr_args: Vec<Expr> = args.iter().map(|a| spec_to_expr(a, env)).collect();110let last = expr_args.remove(expr_args.len() - 1);111112// Reverse to keep the order of the original list113expr_args114.iter()115.rev()116.fold(last, |acc, a| b(Box::new(a.clone()), Box::new(acc)))117}118119match s {120// Unary121SpecOp::Not => unop(Expr::Not, args, pos, env),122SpecOp::BVNot => unop(Expr::BVNot, args, pos, env),123SpecOp::BVNeg => unop(Expr::BVNeg, args, pos, env),124SpecOp::Rev => unop(Expr::Rev, args, pos, env),125SpecOp::Clz => unop(Expr::CLZ, args, pos, env),126SpecOp::Cls => unop(Expr::CLS, args, pos, env),127SpecOp::Popcnt => unop(Expr::BVPopcnt, args, pos, env),128SpecOp::BV2Int => unop(Expr::BVToInt, args, pos, env),129130// Variadic binops131SpecOp::And => variadic_binop(Expr::And, args, pos, env),132SpecOp::Or => variadic_binop(Expr::Or, args, pos, env),133134// Binary135SpecOp::Eq => binop(Expr::Eq, args, pos, env),136SpecOp::Lt => binop(Expr::Lt, args, pos, env),137SpecOp::Lte => binop(Expr::Lte, args, pos, env),138SpecOp::Gt => binop(|x, y| Expr::Lt(y, x), args, pos, env),139SpecOp::Gte => binop(|x, y| Expr::Lte(y, x), args, pos, env),140SpecOp::Imp => binop(Expr::Imp, args, pos, env),141SpecOp::BVAnd => binop(Expr::BVAnd, args, pos, env),142SpecOp::BVOr => binop(Expr::BVOr, args, pos, env),143SpecOp::BVXor => binop(Expr::BVXor, args, pos, env),144SpecOp::BVAdd => binop(Expr::BVAdd, args, pos, env),145SpecOp::BVSub => binop(Expr::BVSub, args, pos, env),146SpecOp::BVMul => binop(Expr::BVMul, args, pos, env),147SpecOp::BVUdiv => binop(Expr::BVUDiv, args, pos, env),148SpecOp::BVUrem => binop(Expr::BVUrem, args, pos, env),149SpecOp::BVSdiv => binop(Expr::BVSDiv, args, pos, env),150SpecOp::BVSrem => binop(Expr::BVSrem, args, pos, env),151SpecOp::BVShl => binop(Expr::BVShl, args, pos, env),152SpecOp::BVLshr => binop(Expr::BVShr, args, pos, env),153SpecOp::BVAshr => binop(Expr::BVAShr, args, pos, env),154SpecOp::BVSaddo => binop(Expr::BVSaddo, args, pos, env),155SpecOp::BVUle => binop(Expr::BVUlte, args, pos, env),156SpecOp::BVUlt => binop(Expr::BVUlt, args, pos, env),157SpecOp::BVUgt => binop(Expr::BVUgt, args, pos, env),158SpecOp::BVUge => binop(Expr::BVUgte, args, pos, env),159SpecOp::BVSlt => binop(Expr::BVSlt, args, pos, env),160SpecOp::BVSle => binop(Expr::BVSlte, args, pos, env),161SpecOp::BVSgt => binop(Expr::BVSgt, args, pos, env),162SpecOp::BVSge => binop(Expr::BVSgte, args, pos, env),163SpecOp::Rotr => binop(Expr::BVRotr, args, pos, env),164SpecOp::Rotl => binop(Expr::BVRotl, args, pos, env),165SpecOp::ZeroExt => match spec_to_usize(&args[0]) {166Some(i) => Expr::BVZeroExtTo(167Box::new(Width::Const(i)),168Box::new(spec_to_expr(&args[1], env)),169),170None => binop(Expr::BVZeroExtToVarWidth, args, pos, env),171},172SpecOp::SignExt => match spec_to_usize(&args[0]) {173Some(i) => Expr::BVSignExtTo(174Box::new(Width::Const(i)),175Box::new(spec_to_expr(&args[1], env)),176),177None => binop(Expr::BVSignExtToVarWidth, args, pos, env),178},179SpecOp::ConvTo => binop(Expr::BVConvTo, args, pos, env),180SpecOp::Concat => {181let cases: Vec<Expr> = args.iter().map(|a| spec_to_expr(a, env)).collect();182Expr::BVConcat(cases)183}184SpecOp::Extract => {185assert_eq!(186args.len(),1873,188"Unexpected number of args for extract operator {pos:?}",189);190Expr::BVExtract(191spec_to_usize(&args[0]).unwrap(),192spec_to_usize(&args[1]).unwrap(),193Box::new(spec_to_expr(&args[2], env)),194)195}196SpecOp::Int2BV => {197assert_eq!(198args.len(),1992,200"Unexpected number of args for Int2BV operator {pos:?}",201);202Expr::BVIntToBv(203spec_to_usize(&args[0]).unwrap(),204Box::new(spec_to_expr(&args[1], env)),205)206}207SpecOp::Subs => {208assert_eq!(209args.len(),2103,211"Unexpected number of args for subs operator {pos:?}",212);213Expr::BVSubs(214Box::new(spec_to_expr(&args[0], env)),215Box::new(spec_to_expr(&args[1], env)),216Box::new(spec_to_expr(&args[2], env)),217)218}219SpecOp::WidthOf => unop(Expr::WidthOf, args, pos, env),220SpecOp::If => {221assert_eq!(222args.len(),2233,224"Unexpected number of args for extract operator {pos:?}",225);226Expr::Conditional(227Box::new(spec_to_expr(&args[0], env)),228Box::new(spec_to_expr(&args[1], env)),229Box::new(spec_to_expr(&args[2], env)),230)231}232SpecOp::Switch => {233assert!(234args.len() > 1,235"Unexpected number of args for switch operator {pos:?}",236);237let swith_on = spec_to_expr(&args[0], env);238let arms: Vec<(Expr, Expr)> = args[1..]239.iter()240.map(|a| match a {241SpecExpr::Pair { l, r } => {242let l_expr = spec_to_expr(l, env);243let r_expr = spec_to_expr(r, env);244(l_expr, r_expr)245}246_ => unreachable!(),247})248.collect();249Expr::Switch(Box::new(swith_on), arms)250}251SpecOp::LoadEffect => {252assert_eq!(253args.len(),2543,255"Unexpected number of args for load operator {pos:?}",256);257Expr::LoadEffect(258Box::new(spec_to_expr(&args[0], env)),259Box::new(spec_to_expr(&args[1], env)),260Box::new(spec_to_expr(&args[2], env)),261)262}263SpecOp::StoreEffect => {264assert_eq!(265args.len(),2664,267"Unexpected number of args for store operator {pos:?}",268);269Expr::StoreEffect(270Box::new(spec_to_expr(&args[0], env)),271Box::new(spec_to_expr(&args[1], env)),272Box::new(spec_to_expr(&args[2], env)),273Box::new(spec_to_expr(&args[3], env)),274)275}276}277}278279fn spec_to_expr(s: &SpecExpr, env: &ParsingEnv) -> Expr {280match s {281SpecExpr::ConstUnit { pos: _ } => Expr::Const(Const {282ty: Type::Unit,283value: 0,284width: 0,285}),286SpecExpr::ConstInt { val, pos: _ } => Expr::Const(Const {287ty: Type::Int,288value: *val,289width: 0,290}),291SpecExpr::ConstBitVec { val, width, pos: _ } => Expr::Const(Const {292ty: Type::BitVectorWithWidth(*width as usize),293value: *val,294width: (*width as usize),295}),296SpecExpr::ConstBool { val, pos: _ } => Expr::Const(Const {297ty: Type::Bool,298value: *val as i128,299width: 0,300}),301SpecExpr::Var { var, pos: _ } => Expr::Var(var.0.clone()),302SpecExpr::Op { op, args, pos } => spec_op_to_expr(op, args, pos, env),303SpecExpr::Pair { l, r } => {304unreachable!("pairs currently only parsed as part of Switch statements, {l:?} {r:?}",)305}306SpecExpr::Enum { name } => {307if let Some(e) = env.enums.get(&name.0) {308e.clone()309} else {310panic!("Can't find model for enum {}", name.0);311}312}313}314}315316fn model_type_to_type(model_type: &ModelType) -> veri_ir::Type {317match model_type {318ModelType::Int => veri_ir::Type::Int,319ModelType::Unit => veri_ir::Type::Unit,320ModelType::Bool => veri_ir::Type::Bool,321ModelType::BitVec(size) => veri_ir::Type::BitVector(*size),322}323}324325fn signature_to_term_type_signature(sig: &Signature) -> TermTypeSignature {326TermTypeSignature {327args: sig.args.iter().map(model_type_to_type).collect(),328ret: model_type_to_type(&sig.ret),329canonical_type: Some(model_type_to_type(&sig.canonical)),330}331}332333pub fn parse_annotations(defs: &[Def], termenv: &TermEnv, typeenv: &TypeEnv) -> AnnotationEnv {334let mut annotation_map = HashMap::new();335let mut model_map = HashMap::new();336337let mut env = ParsingEnv {338typeenv,339enums: HashMap::new(),340};341342// Traverse models to process spec annotations for enums343for def in defs {344if let &ast::Def::Model(Model { ref name, ref val }) = def {345match val {346ast::ModelValue::TypeValue(model_type) => {347let type_id = typeenv.get_type_by_name(name).unwrap();348let ir_type = match model_type {349ModelType::Int => annotation_ir::Type::Int,350ModelType::Unit => annotation_ir::Type::Unit,351ModelType::Bool => annotation_ir::Type::Bool,352ModelType::BitVec(None) => annotation_ir::Type::BitVector,353ModelType::BitVec(Some(size)) => {354annotation_ir::Type::BitVectorWithWidth(*size)355}356};357model_map.insert(type_id, ir_type);358}359ast::ModelValue::EnumValues(vals) => {360for (v, e) in vals {361let ident = ast::Ident(format!("{}.{}", name.0, v.0), v.1);362let term_id = termenv.get_term_by_name(typeenv, &ident).unwrap();363let val = spec_to_expr(e, &env);364let ty = match val {365Expr::Const(Const { ref ty, .. }) => ty,366_ => unreachable!(),367};368env.enums.insert(ident.0.clone(), val.clone());369let result = BoundVar {370name: RESULT.to_string(),371ty: Some(ty.clone()),372};373let sig = TermSignature {374args: vec![],375ret: result,376};377let annotation = TermAnnotation {378sig,379assumptions: vec![Box::new(Expr::Eq(380Box::new(Expr::Var(RESULT.to_string())),381Box::new(val),382))],383assertions: vec![],384};385annotation_map.insert(term_id, annotation);386}387}388}389}390}391392// Traverse defs to process spec annotations393for def in defs {394if let ast::Def::Spec(spec) = def {395let termname = spec.term.0.clone();396let term_id = termenv397.get_term_by_name(typeenv, &spec.term)398.unwrap_or_else(|| panic!("Spec provided for unknown decl {termname}"));399assert!(400!annotation_map.contains_key(&term_id),401"duplicate spec for {termname}",402);403let sig = TermSignature {404args: spec.args.iter().map(spec_to_annotation_bound_var).collect(),405ret: BoundVar {406name: RESULT.to_string(),407ty: None,408},409};410411let mut assumptions = vec![];412let mut assertions = vec![];413for a in &spec.provides {414assumptions.push(Box::new(spec_to_expr(a, &env)));415}416417for a in &spec.requires {418assertions.push(Box::new(spec_to_expr(a, &env)));419}420421let annotation = TermAnnotation {422sig,423assumptions,424assertions,425};426annotation_map.insert(term_id, annotation);427}428}429430// Collect term instantiations.431let mut forms_map = HashMap::new();432for def in defs {433if let ast::Def::Form(form) = def {434let term_type_signatures: Vec<_> = form435.signatures436.iter()437.map(signature_to_term_type_signature)438.collect();439forms_map.insert(form.name.0.clone(), term_type_signatures);440}441}442443let mut instantiations_map = HashMap::new();444for def in defs {445if let ast::Def::Instantiation(inst) = def {446let term_id = termenv.get_term_by_name(typeenv, &inst.term).unwrap();447let sigs = match &inst.form {448Some(form) => forms_map[&form.0].clone(),449None => inst450.signatures451.iter()452.map(signature_to_term_type_signature)453.collect(),454};455instantiations_map.insert(term_id, sigs);456}457}458459AnnotationEnv {460annotation_map,461instantiations_map,462model_map,463}464}465466467