Path: blob/main/cranelift/isle/veri/veri_ir/src/lib.rs
1693 views
//! Verification Intermediate Representation for relevant types, eventually to1//! be lowered to SMT. The goal is to leave some freedom to change term2//! encodings or the specific solver backend.3//!4//! Note: annotations use the higher-level IR in annotation_ir.rs.5pub mod annotation_ir;6use core::fmt;7use std::collections::HashMap;89#[derive(Clone, Debug, PartialEq, Eq)]10pub struct TypeContext {11pub tyvars: HashMap<Expr, u32>,12pub tymap: HashMap<u32, Type>,13pub tyvals: HashMap<u32, i128>,14// map of type var to set index15pub bv_unknown_width_sets: HashMap<u32, u32>,16}1718// Used for providing concrete inputs to test rule semantics19#[derive(Clone, Debug, PartialEq, Eq)]20pub struct ConcreteInput {21// SMT-LIB-formatted bitvector literal22pub literal: String,23pub ty: Type,24}25#[derive(Clone, Debug, PartialEq, Eq)]26pub struct ConcreteTest {27pub termname: String,28// List of name, bitvector literal, widths29pub args: Vec<ConcreteInput>,30pub output: ConcreteInput,31}3233/// A bound variable, including the VIR type34#[derive(Clone, Debug, PartialEq, Eq, Hash)]35pub struct BoundVar {36pub name: String,37pub tyvar: u32,38}3940/// Verification type41#[derive(Clone, Debug, PartialEq, Eq, Hash, Copy)]42pub enum Type {43/// The expression is a bitvector, currently modeled in the44/// logic QF_BV https://SMT-LIB.cs.uiowa.edu/version1/logics/QF_BV.smt45/// This corresponds to Cranelift's Isle type:46/// (type Value (primitive Value))47BitVector(Option<usize>),4849/// The expression is a boolean. This does not directly correspond50/// to a specific Cranelift Isle type, rather, we use it for the51/// language of assertions.52Bool,5354/// The expression is an Isle type. This is separate from BitVector55/// because it allows us to use a different solver type (e.h., Int)56//. for assertions (e.g., fits_in_64).57/// This corresponds to Cranelift's Isle type:58/// (type Type (primitive Type))59Int,6061Unit,62}6364impl fmt::Display for Type {65fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {66match self {67Type::BitVector(None) => write!(f, "bv"),68Type::BitVector(Some(s)) => write!(f, "(bv {})", *s),69Type::Bool => write!(f, "Bool"),70Type::Int => write!(f, "Int"),71Type::Unit => write!(f, "Unit"),72}73}74}7576#[derive(Clone, Debug, PartialEq, Eq, Hash)]77pub struct TermSignature {78pub args: Vec<Type>,79pub ret: Type,8081// Which type varies for different bitwidth Values, that is, the type that82// is used as a key for testing for that type.83pub canonical_type: Option<Type>,84}8586impl fmt::Display for TermSignature {87fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {88let args = self89.args90.iter()91.map(|a| a.to_string())92.collect::<Vec<_>>()93.join(" ");94let canon = self95.canonical_type96.map(|c| format!("(canon {c})"))97.unwrap_or_default();98write!(f, "((args {}) (ret {}) {})", args, self.ret, canon)99}100}101102#[derive(Clone, Debug, PartialEq, Eq, Hash)]103pub enum Terminal {104Var(String),105106// Literal SMT value, for testing (plus type variable)107Literal(String, u32),108109// Value, type variable110Const(i128, u32),111True,112False,113Wildcard(u32),114}115116#[derive(Clone, Debug, PartialEq, Eq, Hash)]117pub enum UnaryOp {118// Boolean operations119Not,120121// Bitvector operations122BVNeg,123BVNot,124}125126#[derive(Clone, Debug, PartialEq, Eq, Hash)]127pub enum BinaryOp {128// Boolean operations129And,130Or,131Imp,132Eq,133Lte,134Lt,135136// Bitvector operations137BVSgt,138BVSgte,139BVSlt,140BVSlte,141BVUgt,142BVUgte,143BVUlt,144BVUlte,145146BVMul,147BVUDiv,148BVSDiv,149BVAdd,150BVSub,151BVUrem,152BVSrem,153BVAnd,154BVOr,155BVXor,156BVRotl,157BVRotr,158BVShl,159BVShr,160BVAShr,161162BVSaddo,163}164165/// Expressions (combined across all types).166#[derive(Clone, Debug, PartialEq, Eq, Hash)]167pub enum Expr {168// Terminal nodes169Terminal(Terminal),170171// Opcode nodes172Unary(UnaryOp, Box<Expr>),173Binary(BinaryOp, Box<Expr>, Box<Expr>),174175// Count leading zeros176CLZ(Box<Expr>),177CLS(Box<Expr>),178Rev(Box<Expr>),179180BVPopcnt(Box<Expr>),181182BVSubs(Box<Expr>, Box<Expr>, Box<Expr>),183184// ITE185Conditional(Box<Expr>, Box<Expr>, Box<Expr>),186187// Switch188Switch(Box<Expr>, Vec<(Expr, Expr)>),189190// Conversions191// Extract specified bits192BVExtract(usize, usize, Box<Expr>),193194// Concat bitvectors195BVConcat(Vec<Expr>),196197// Convert integer to bitvector with that value198BVIntToBV(usize, Box<Expr>),199200// Convert bitvector to integer with that value201BVToInt(Box<Expr>),202203// Zero extend, with static or dynamic width204BVZeroExtTo(usize, Box<Expr>),205BVZeroExtToVarWidth(Box<Expr>, Box<Expr>),206207// Sign extend, with static or dynamic width208BVSignExtTo(usize, Box<Expr>),209BVSignExtToVarWidth(Box<Expr>, Box<Expr>),210211// Conversion to wider/narrower bits, without an explicit extend212BVConvTo(Box<Expr>, Box<Expr>),213214WidthOf(Box<Expr>),215216LoadEffect(Box<Expr>, Box<Expr>, Box<Expr>),217StoreEffect(Box<Expr>, Box<Expr>, Box<Expr>, Box<Expr>),218}219220impl fmt::Display for Expr {221fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {222match self {223Expr::Terminal(t) => match t {224Terminal::Var(v) => write!(f, "{v}"),225Terminal::Literal(v, _) => write!(f, "{v}"),226Terminal::Const(c, _) => write!(f, "{c}"),227Terminal::True => write!(f, "true"),228Terminal::False => write!(f, "false"),229Terminal::Wildcard(_) => write!(f, "_"),230},231Expr::Unary(o, e) => {232let op = match o {233UnaryOp::Not => "not",234UnaryOp::BVNeg => "bvneg",235UnaryOp::BVNot => "bvnot",236};237write!(f, "({op} {e})")238}239Expr::Binary(o, x, y) => {240let op = match o {241BinaryOp::And => "and",242BinaryOp::Or => "or",243BinaryOp::Imp => "=>",244BinaryOp::Eq => "=",245BinaryOp::Lte => "<=",246BinaryOp::Lt => "<",247BinaryOp::BVSgt => "bvsgt",248BinaryOp::BVSgte => "bvsgte",249BinaryOp::BVSlt => "bvslt",250BinaryOp::BVSlte => "bvslte",251BinaryOp::BVUgt => "bvugt",252BinaryOp::BVUgte => "bvugte",253BinaryOp::BVUlt => "bvult",254BinaryOp::BVUlte => "bvulte",255BinaryOp::BVMul => "bvmul",256BinaryOp::BVUDiv => "bvudiv",257BinaryOp::BVSDiv => "bvsdiv",258BinaryOp::BVAdd => "bvadd",259BinaryOp::BVSub => "bvsub",260BinaryOp::BVUrem => "bvurem",261BinaryOp::BVSrem => "bvsrem",262BinaryOp::BVAnd => "bvand",263BinaryOp::BVOr => "bvor",264BinaryOp::BVXor => "bvxor",265BinaryOp::BVRotl => "rotl",266BinaryOp::BVRotr => "rotr",267BinaryOp::BVShl => "bvshl",268BinaryOp::BVShr => "bvshr",269BinaryOp::BVAShr => "bvashr",270BinaryOp::BVSaddo => "bvsaddo",271};272write!(f, "({op} {x} {y})")273}274Expr::CLZ(e) => write!(f, "(clz {e})"),275Expr::CLS(e) => write!(f, "(cls {e})"),276Expr::Rev(e) => write!(f, "(rev {e})"),277Expr::BVPopcnt(e) => write!(f, "(popcnt {e})"),278Expr::BVSubs(t, x, y) => write!(f, "(subs {t} {x} {y})"),279Expr::Conditional(c, t, e) => write!(f, "(if {c} {t} {e})"),280Expr::Switch(m, cs) => {281let cases: Vec<String> = cs.iter().map(|(c, m)| format!("({c} {m})")).collect();282write!(f, "(switch {m} {})", cases.join(""))283}284Expr::BVExtract(h, l, e) => write!(f, "(extract {h} {l} {e})"),285Expr::BVConcat(es) => {286let vs: Vec<String> = es.iter().map(|v| format!("{v}")).collect();287write!(f, "(concat {})", vs.join(""))288}289Expr::BVIntToBV(t, e) => write!(f, "(int2bv {t} {e})"),290Expr::BVToInt(b) => write!(f, "(bv2int {b})"),291Expr::BVZeroExtTo(d, e) => write!(f, "(zero_ext {d} {e})"),292Expr::BVZeroExtToVarWidth(d, e) => write!(f, "(zero_ext {d} {e})"),293Expr::BVSignExtTo(d, e) => write!(f, "(sign_ext {d} {e})"),294Expr::BVSignExtToVarWidth(d, e) => write!(f, "(sign_ext {d} {e})"),295Expr::BVConvTo(x, y) => write!(f, "(conv_to {x} {y})"),296Expr::WidthOf(e) => write!(f, "(widthof {e})"),297Expr::LoadEffect(x, y, z) => write!(f, "(load_effect {x} {y} {z})"),298Expr::StoreEffect(w, x, y, z) => write!(f, "(store_effect {w} {x} {y} {z})"),299}300}301}302303/// To-be-flushed-out verification counterexample for failures304#[derive(Clone, Debug, PartialEq, Eq)]305pub struct Counterexample {}306307/// To-be-flushed-out verification result308#[derive(Clone, Debug, PartialEq, Eq)]309pub enum VerificationResult {310InapplicableRule,311Success,312Failure(Counterexample),313Unknown,314// Optional: heuristic that a rule is bad if there is only315// a single model with distinct bitvector inputs316NoDistinctModels,317}318319320