Skip to main content

litex/verify/
verify_or_fact.rs

1use crate::prelude::*;
2use crate::verify::verify_equality_by_builtin_rules::objs_equal_by_display_string;
3use std::result::Result;
4
5/// Two atomic facts of the form `s > t` / `s <= t` (or `<` / `>=`) with the same left and right
6/// operands; the disjunction is a trivial order split (totally ordered carriers such as `R`).
7fn order_split_or_is_exhaustive_pair(a: &AtomicFact, b: &AtomicFact) -> bool {
8    use AtomicFact::*;
9    match (a, b) {
10        (GreaterFact(g), LessEqualFact(le)) => {
11            objs_equal_by_display_string(&g.left, &le.left)
12                && objs_equal_by_display_string(&g.right, &le.right)
13        }
14        (LessFact(l), GreaterEqualFact(ge)) => {
15            objs_equal_by_display_string(&l.left, &ge.left)
16                && objs_equal_by_display_string(&l.right, &ge.right)
17        }
18        (LessEqualFact(le), GreaterFact(g)) => {
19            objs_equal_by_display_string(&le.left, &g.left)
20                && objs_equal_by_display_string(&le.right, &g.right)
21        }
22        (GreaterEqualFact(ge), LessFact(l)) => {
23            objs_equal_by_display_string(&ge.left, &l.left)
24                && objs_equal_by_display_string(&ge.right, &l.right)
25        }
26        _ => false,
27    }
28}
29
30fn obj_is_literal_neg_one_for_abs_or_builtin(obj: &Obj) -> bool {
31    match obj {
32        Obj::Number(n) => n.normalized_value == "-1",
33        _ => false,
34    }
35}
36
37fn obj_is_negation_of_for_abs_or_builtin(obj: &Obj, expected_arg: &Obj) -> bool {
38    match obj {
39        Obj::Mul(m) => {
40            (obj_is_literal_neg_one_for_abs_or_builtin(m.left.as_ref())
41                && objs_equal_by_display_string(m.right.as_ref(), expected_arg))
42                || (obj_is_literal_neg_one_for_abs_or_builtin(m.right.as_ref())
43                    && objs_equal_by_display_string(m.left.as_ref(), expected_arg))
44        }
45        _ => false,
46    }
47}
48
49fn abs_sign_split_or_is_exhaustive_pair(a: &AtomicFact, b: &AtomicFact) -> bool {
50    let (AtomicFact::EqualFact(first), AtomicFact::EqualFact(second)) = (a, b) else {
51        return false;
52    };
53    let (arg, first_other) = match (&first.left, &first.right) {
54        (Obj::Abs(abs), other) => (abs.arg.as_ref(), other),
55        (other, Obj::Abs(abs)) => (abs.arg.as_ref(), other),
56        _ => return false,
57    };
58    if !objs_equal_by_display_string(arg, first_other) {
59        return false;
60    }
61    let (second_arg, second_other) = match (&second.left, &second.right) {
62        (Obj::Abs(abs), other) => (abs.arg.as_ref(), other),
63        (other, Obj::Abs(abs)) => (abs.arg.as_ref(), other),
64        _ => return false,
65    };
66    objs_equal_by_display_string(arg, second_arg)
67        && obj_is_negation_of_for_abs_or_builtin(second_other, arg)
68}
69
70impl Runtime {
71    pub fn verify_or_fact(
72        &mut self,
73        or_fact: &OrFact,
74        verify_state: &VerifyState,
75    ) -> Result<StmtResult, RuntimeError> {
76        if let Some(cached_result) =
77            self.verify_fact_from_cache_using_display_string(&or_fact.clone().into())
78        {
79            return Ok(cached_result);
80        }
81
82        if !verify_state.well_defined_already_verified {
83            if let Err(e) = self.verify_or_fact_well_defined(or_fact, verify_state) {
84                return Err({
85                    VerifyRuntimeError(RuntimeErrorStruct::new(
86                        Some(Fact::from(or_fact.clone()).into_stmt()),
87                        String::new(),
88                        or_fact.line_file.clone(),
89                        Some(e),
90                        vec![],
91                    ))
92                    .into()
93                });
94            }
95        }
96
97        let verify_state_for_children = verify_state.make_state_with_req_ok_set_to_true();
98
99        if or_fact.facts.len() == 2 {
100            if let (
101                AndChainAtomicFact::AtomicFact(first_atomic),
102                AndChainAtomicFact::AtomicFact(second_atomic),
103            ) = (&or_fact.facts[0], &or_fact.facts[1])
104            {
105                if first_atomic.make_reversed().to_string() == second_atomic.to_string() {
106                    return Ok(
107                        (FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
108                            or_fact.clone().into(),
109                            "or: complementary atomic facts (make_reversed first equals second)"
110                                .to_string(),
111                            Vec::new(),
112                        ))
113                        .into(),
114                    );
115                }
116                if order_split_or_is_exhaustive_pair(first_atomic, second_atomic)
117                    || order_split_or_is_exhaustive_pair(second_atomic, first_atomic)
118                {
119                    return Ok(
120                        (FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
121                            or_fact.clone().into(),
122                            "or: complementary order relations (strict vs non-strict) on the same terms"
123                                .to_string(),
124                            Vec::new(),
125                        ))
126                        .into(),
127                    );
128                }
129                if abs_sign_split_or_is_exhaustive_pair(first_atomic, second_atomic)
130                    || abs_sign_split_or_is_exhaustive_pair(second_atomic, first_atomic)
131                {
132                    return Ok(
133                        (FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
134                            or_fact.clone().into(),
135                            "or: abs(x) is x or -x".to_string(),
136                            Vec::new(),
137                        ))
138                        .into(),
139                    );
140                }
141            }
142        }
143
144        for fact in or_fact.facts.iter() {
145            let result = self.verify_and_chain_atomic_fact(fact, &verify_state_for_children)?;
146            if result.is_true() {
147                return Ok(
148                    (FactualStmtSuccess::new_with_verified_by_known_fact_source_recording_facts(
149                        or_fact.clone().into(),
150                        fact.to_string(),
151                        None,
152                        Some(fact.line_file()),
153                        Vec::new(),
154                    ))
155                    .into(),
156                );
157            }
158        }
159
160        let result = self.verify_or_fact_with_known_or_facts(or_fact)?;
161        if result.is_true() {
162            return Ok(result);
163        }
164
165        let result = self.verify_or_fact_with_known_forall(or_fact, verify_state)?;
166        if result.is_true() {
167            return Ok(result);
168        }
169
170        Ok((StmtUnknown::new()).into())
171    }
172
173    pub fn verify_or_fact_with_known_or_facts(
174        &mut self,
175        or_fact: &OrFact,
176    ) -> Result<StmtResult, RuntimeError> {
177        let args_in_or_fact = or_fact.get_args_from_fact();
178        let mut all_objs_equal_to_each_arg: Vec<Vec<String>> = Vec::new();
179        for arg in args_in_or_fact.iter() {
180            let mut all_objs_equal_to_current_arg =
181                self.get_all_objs_equal_to_given(&arg.to_string());
182            if all_objs_equal_to_current_arg.is_empty() {
183                all_objs_equal_to_current_arg.push(arg.to_string());
184            }
185            all_objs_equal_to_each_arg.push(all_objs_equal_to_current_arg);
186        }
187
188        for environment in self.iter_environments_from_top() {
189            let result = Self::verify_or_fact_with_known_or_facts_with_facts_in_environment(
190                environment,
191                or_fact,
192                &all_objs_equal_to_each_arg,
193            )?;
194            if result.is_true() {
195                return Ok(result);
196            }
197        }
198
199        Ok((StmtUnknown::new()).into())
200    }
201
202    pub fn verify_or_fact_with_known_or_facts_with_facts_in_environment(
203        environment: &Environment,
204        or_fact: &OrFact,
205        all_objs_equal_to_each_arg: &Vec<Vec<String>>,
206    ) -> Result<StmtResult, RuntimeError> {
207        if let Some(known_or_facts) = environment.known_or_facts.get(&or_fact.key()) {
208            for known_or_fact in known_or_facts.iter() {
209                let result = Self::_verify_or_fact_the_same_type_and_return_matched_args(
210                    known_or_fact,
211                    or_fact,
212                )?;
213                let mut all_args_match = true;
214                if let Some(matched_args) = result {
215                    for (index, matched_arg) in matched_args.iter().enumerate() {
216                        let known_arg_string = matched_arg.0.to_string();
217
218                        if known_arg_string != matched_arg.1.to_string()
219                            && !all_objs_equal_to_each_arg[index].contains(&known_arg_string)
220                        {
221                            all_args_match = false;
222                            break;
223                        }
224                    }
225                }
226
227                if all_args_match {
228                    return Ok((FactualStmtSuccess::new_with_verified_by_known_fact_source_recording_facts(
229                            or_fact.clone().into(),
230                            known_or_fact.to_string(),
231                            Some(known_or_fact.clone().into()),
232                            None,
233                            Vec::new(),
234                        )).into());
235                }
236            }
237        }
238
239        return Ok((StmtUnknown::new()).into());
240    }
241}