machine_check_common/iir/
stmt.rs1use std::fmt::Debug;
2
3use mck::{
4 abstr::{AbstractValue, BitvectorDomain},
5 misc::BitvectorBound,
6 ParamValuation,
7};
8use serde::{Deserialize, Serialize};
9
10use crate::{
11 iir::{
12 context::{IContext, IFnContext},
13 expr::IExpr,
14 func::IBlock,
15 ty::{IElementaryType, IGeneralType, IType},
16 variable::IVarId,
17 IAbstr, IRefin,
18 },
19 ir_common::IrReference,
20};
21
22#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
23pub enum IStmt {
24 Assign(IAssignStmt),
25 If(IIfStmt),
26}
27
28impl IStmt {
29 pub fn forward_interpret(&self, context: &IFnContext, abstr: &mut IAbstr) {
30 match self {
31 IStmt::Assign(stmt_assign) => stmt_assign.forward_interpret(context, abstr),
32 IStmt::If(stmt_if) => stmt_if.forward_interpret(context, abstr),
33 }
34 }
35
36 pub fn backward_interpret(&self, context: &IFnContext, abstr: &IAbstr, refin: &mut IRefin) {
37 match self {
38 IStmt::Assign(stmt_assign) => stmt_assign.backward_interpret(context, abstr, refin),
39 IStmt::If(stmt_if) => stmt_if.backward_interpret(context, abstr, refin),
40 }
41 }
42}
43
44#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
45pub struct IAssignStmt {
46 pub left: IVarId,
47 pub right: IExpr,
48}
49
50impl IAssignStmt {
51 fn forward_interpret(&self, context: &IFnContext, abstr: &mut IAbstr) {
52 let left_var_id = self.left;
53 if let Some(left_value) = self.right.forward_interpret(context, abstr) {
54 let left_type = &context
55 .func
56 .variables
57 .get(&left_var_id)
58 .expect("Function variable should have type")
59 .ty;
60
61 ensure_abstract_general_type(context.context, &left_value, left_type);
62
63 abstr.insert_value(left_var_id, left_value);
64 }
65 }
66
67 pub fn backward_interpret(&self, context: &IFnContext, abstr: &IAbstr, refin: &mut IRefin) {
68 let left_ident = self.left;
75 if let Some(later_refinement_value) = refin.value_opt(left_ident) {
76 self.right
77 .backward_interpret(context, abstr, refin, later_refinement_value.clone());
78 }
79 }
80}
81
82#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
83pub struct IIfStmt {
84 pub condition: IVarId,
85 pub then_block: IBlock,
86 pub else_block: IBlock,
87}
88
89impl IIfStmt {
90 fn forward_interpret(&self, context: &IFnContext, abstr: &mut IAbstr) {
91 let (can_take_then, can_take_else) = self.can_take_then_else(abstr);
92 if can_take_then {
93 self.then_block.forward_interpret(context, abstr);
94 }
95 if can_take_else {
96 self.else_block.forward_interpret(context, abstr);
97 }
98 }
99
100 pub fn backward_interpret(&self, context: &IFnContext, abstr: &IAbstr, refin: &mut IRefin) {
101 let (can_take_then, can_take_else) = self.can_take_then_else(abstr);
102 if can_take_then {
103 self.then_block.backward_interpret(context, abstr, refin);
104 }
105 if can_take_else {
106 self.else_block.backward_interpret(context, abstr, refin);
107 }
108 }
109
110 fn can_take_then_else(&self, abstr: &IAbstr) -> (bool, bool) {
111 let condition_value = abstr.value(self.condition);
112
113 let AbstractValue::Boolean(condition_value) = condition_value else {
114 panic!("Condition value should be bool");
115 };
116
117 let condition_value = condition_value.value();
118
119 let can_take_then = matches!(
120 condition_value,
121 ParamValuation::True | ParamValuation::Unknown | ParamValuation::Dependent
122 );
123 let can_take_else = matches!(
124 condition_value,
125 ParamValuation::False | ParamValuation::Unknown | ParamValuation::Dependent
126 );
127
128 (can_take_then, can_take_else)
129 }
130}
131
132impl Debug for IStmt {
133 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
134 match self {
135 IStmt::Assign(assign_stmt) => assign_stmt.fmt(f),
136 IStmt::If(if_stmt) => if_stmt.fmt(f),
137 }
138 }
139}
140
141impl Debug for IAssignStmt {
142 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
143 write!(f, "{:?} = {:?}", self.left, self.right)
144 }
145}
146
147impl Debug for IIfStmt {
148 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
149 write!(f, "if {:?} ", self.condition)?;
150
151 let mut franz = f.debug_set();
152 for stmt in &self.then_block.stmts {
153 franz.entry(stmt);
154 }
155 franz.finish()?;
156
157 write!(f, " else ")?;
158
159 let mut franz = f.debug_set();
160 for stmt in &self.else_block.stmts {
161 franz.entry(stmt);
162 }
163 franz.finish()?;
164
165 Ok(())
166 }
167}
168
169fn ensure_abstract_general_type(context: &IContext, value: &AbstractValue, ty: &IGeneralType) {
170 match ty {
171 IGeneralType::Normal(ty) => ensure_abstract_type(context, value, ty),
172 IGeneralType::PanicResult(ty) => {
173 let AbstractValue::Struct(fields) = value else {
174 panic!("Expected panic result type of value (represented by fields)");
175 };
176 assert_eq!(fields.len(), 2);
177 ensure_abstract_type(context, &fields[0], ty);
178 ensure_abstract_type(
179 context,
180 &fields[1],
181 &IType {
182 reference: IrReference::None,
183 inner: IElementaryType::Bitvector(32),
184 },
185 );
186 }
187 IGeneralType::PhiArg(ty) => ensure_abstract_type(context, value, ty),
188 }
189}
190
191fn ensure_abstract_type(context: &IContext, value: &AbstractValue, ty: &IType) {
192 match &ty.inner {
193 IElementaryType::Bitvector(width) => {
194 let AbstractValue::Bitvector(bitvector) = value else {
195 panic!("Expected bitvector type of value");
196 };
197
198 assert_eq!(*width, bitvector.bound().width());
199 }
200 IElementaryType::Array(array_type) => {
201 let AbstractValue::Array(array) = value else {
202 panic!("Expected array type of value");
203 };
204
205 assert_eq!(array_type.index_width, array.index_bound().width());
206 assert_eq!(array_type.element_width, array.element_bound().width());
207 }
208 IElementaryType::Boolean => {
209 let AbstractValue::Boolean(_) = value else {
210 panic!("Expected boolean type of value");
211 };
212 }
213 IElementaryType::Struct(struct_id) => {
214 let AbstractValue::Struct(fields) = value else {
215 panic!("Expected struct type of value");
216 };
217
218 let struct_data = context.struct_with_id(*struct_id);
219 assert_eq!(fields.len(), struct_data.fields.len());
220
221 for (value, ty) in fields.iter().zip(struct_data.fields.values()) {
222 ensure_abstract_type(
223 context,
224 value,
225 &IType {
226 reference: IrReference::None,
227 inner: ty.clone(),
228 },
229 );
230 }
231 }
232 }
233}