Skip to main content

litex/runtime/
runtime_resolve_obj.rs

1use crate::common::count_range_integer::{
2    count_closed_range_integer_endpoints, count_half_open_range_integer_endpoints,
3};
4use crate::prelude::*;
5use crate::verify::{compare_normalized_number_str_to_zero, NumberCompareResult};
6
7impl Runtime {
8    pub fn resolve_obj_to_number(&self, obj: &Obj) -> Option<Number> {
9        if let Some(number) = obj.evaluate_to_normalized_decimal_number() {
10            return Some(number);
11        }
12        self.get_object_equal_to_normalized_decimal_number(&obj.to_string())
13    }
14
15    pub fn resolve_obj_to_number_resolved(&self, obj: &Obj) -> Option<Number> {
16        self.resolve_obj_to_number(&self.resolve_obj(obj))
17    }
18
19    // After resolving children, fold literals; if still not a number, use
20    // `known_objs_equal_to_normalized_decimal_number` so e.g. `a - b` becomes `100` when that
21    // binding exists, then outer `(... - 10)` can evaluate (used by equality `calculation`).
22    fn resolve_obj_try_fold_arithmetic(&self, result: Obj) -> Obj {
23        if let Some(calculated) = result.evaluate_to_normalized_decimal_number() {
24            return calculated.into();
25        }
26        if let Some(n) = self.resolve_obj_to_number(&result) {
27            return n.into();
28        }
29        result
30    }
31
32    pub fn resolve_obj(&self, obj: &Obj) -> Obj {
33        match obj {
34            Obj::Number(number) => number.clone().into(),
35            Obj::Add(add) => {
36                let result: Obj =
37                    Add::new(self.resolve_obj(&add.left), self.resolve_obj(&add.right)).into();
38                self.resolve_obj_try_fold_arithmetic(result)
39            }
40            Obj::Sub(sub) => {
41                let result: Obj =
42                    Sub::new(self.resolve_obj(&sub.left), self.resolve_obj(&sub.right)).into();
43                self.resolve_obj_try_fold_arithmetic(result)
44            }
45            Obj::Mul(mul) => {
46                let result: Obj =
47                    Mul::new(self.resolve_obj(&mul.left), self.resolve_obj(&mul.right)).into();
48                self.resolve_obj_try_fold_arithmetic(result)
49            }
50            Obj::Mod(mod_obj) => {
51                let result: Obj = Mod::new(
52                    self.resolve_obj(&mod_obj.left),
53                    self.resolve_obj(&mod_obj.right),
54                )
55                .into();
56                self.resolve_obj_try_fold_arithmetic(result)
57            }
58            Obj::Pow(pow) => {
59                let result: Obj =
60                    Pow::new(self.resolve_obj(&pow.base), self.resolve_obj(&pow.exponent)).into();
61                self.resolve_obj_try_fold_arithmetic(result)
62            }
63            Obj::Div(div) => {
64                let result: Obj =
65                    Div::new(self.resolve_obj(&div.left), self.resolve_obj(&div.right)).into();
66                self.resolve_obj_try_fold_arithmetic(result)
67            }
68            Obj::Abs(a) => {
69                let result: Obj = Abs::new(self.resolve_obj(&a.arg)).into();
70                self.resolve_obj_try_fold_arithmetic(result)
71            }
72            Obj::Max(m) => {
73                let result: Obj =
74                    Max::new(self.resolve_obj(&m.left), self.resolve_obj(&m.right)).into();
75                self.resolve_obj_try_fold_arithmetic(result)
76            }
77            Obj::Min(m) => {
78                let result: Obj =
79                    Min::new(self.resolve_obj(&m.left), self.resolve_obj(&m.right)).into();
80                self.resolve_obj_try_fold_arithmetic(result)
81            }
82            Obj::Log(l) => {
83                let result: Obj =
84                    Log::new(self.resolve_obj(&l.base), self.resolve_obj(&l.arg)).into();
85                self.resolve_obj_try_fold_arithmetic(result)
86            }
87            Obj::FiniteSeqSet(fs) => {
88                FiniteSeqSet::new(self.resolve_obj(&fs.set), self.resolve_obj(&fs.n)).into()
89            }
90            Obj::SeqSet(ss) => SeqSet::new(self.resolve_obj(&ss.set)).into(),
91            Obj::MatrixSet(ms) => MatrixSet::new(
92                self.resolve_obj(&ms.set),
93                self.resolve_obj(&ms.row_len),
94                self.resolve_obj(&ms.col_len),
95            )
96            .into(),
97            Obj::FiniteSeqListObj(list) => {
98                let objs: Vec<Obj> = list.objs.iter().map(|o| self.resolve_obj(o)).collect();
99                FiniteSeqListObj::new(objs).into()
100            }
101            Obj::MatrixListObj(matrix) => {
102                let rows: Vec<Vec<Obj>> = matrix
103                    .rows
104                    .iter()
105                    .map(|row| row.iter().map(|o| self.resolve_obj(o)).collect())
106                    .collect();
107                MatrixListObj::new(rows).into()
108            }
109            Obj::FnObj(fn_obj) => {
110                if fn_obj.body.len() == 1 && fn_obj.body[0].len() == 1 {
111                    let head_key = fn_obj.head.to_string();
112                    if let Some(list) = self.get_obj_equal_to_finite_seq_list(&head_key) {
113                        let arg = self.resolve_obj(fn_obj.body[0][0].as_ref());
114                        if let Some(ix) = self.resolve_obj_to_number(&arg) {
115                            if let Ok(one_based) = ix.normalized_value.parse::<usize>() {
116                                if one_based >= 1 && one_based <= list.objs.len() {
117                                    return (*list.objs[one_based - 1]).clone();
118                                }
119                            }
120                        }
121                    }
122                }
123                if fn_obj.body.len() == 2 && fn_obj.body[0].len() == 1 && fn_obj.body[1].len() == 1
124                {
125                    let head_key = fn_obj.head.to_string();
126                    if let Some(mat) = self.get_obj_equal_to_matrix_list(&head_key) {
127                        let r_arg = self.resolve_obj(fn_obj.body[0][0].as_ref());
128                        let c_arg = self.resolve_obj(fn_obj.body[1][0].as_ref());
129                        if let (Some(rn), Some(cn)) = (
130                            self.resolve_obj_to_number(&r_arg),
131                            self.resolve_obj_to_number(&c_arg),
132                        ) {
133                            if let (Ok(r1), Ok(c1)) = (
134                                rn.normalized_value.parse::<usize>(),
135                                cn.normalized_value.parse::<usize>(),
136                            ) {
137                                if r1 >= 1
138                                    && r1 <= mat.rows.len()
139                                    && c1 >= 1
140                                    && c1 <= mat.rows[r1 - 1].len()
141                                {
142                                    return (*mat.rows[r1 - 1][c1 - 1]).clone();
143                                }
144                            }
145                        }
146                    }
147                }
148                if fn_obj.body.len() == 1 && fn_obj.body[0].len() == 2 {
149                    let head_key = fn_obj.head.to_string();
150                    if let Some(mat) = self.get_obj_equal_to_matrix_list(&head_key) {
151                        let r_arg = self.resolve_obj(fn_obj.body[0][0].as_ref());
152                        let c_arg = self.resolve_obj(fn_obj.body[0][1].as_ref());
153                        if let (Some(rn), Some(cn)) = (
154                            self.resolve_obj_to_number(&r_arg),
155                            self.resolve_obj_to_number(&c_arg),
156                        ) {
157                            if let (Ok(r1), Ok(c1)) = (
158                                rn.normalized_value.parse::<usize>(),
159                                cn.normalized_value.parse::<usize>(),
160                            ) {
161                                if r1 >= 1
162                                    && r1 <= mat.rows.len()
163                                    && c1 >= 1
164                                    && c1 <= mat.rows[r1 - 1].len()
165                                {
166                                    return (*mat.rows[r1 - 1][c1 - 1]).clone();
167                                }
168                            }
169                        }
170                    }
171                }
172                if let Some(number) = self.resolve_obj_to_number(obj) {
173                    number.into()
174                } else {
175                    obj.clone()
176                }
177            }
178            Obj::Atom(AtomObj::Identifier(_)) | Obj::Atom(AtomObj::IdentifierWithMod(_)) => {
179                if let Some(number) = self.resolve_obj_to_number(obj) {
180                    number.into()
181                } else {
182                    obj.clone()
183                }
184            }
185            Obj::Count(count) => match &*count.set {
186                Obj::ListSet(list_set) => Number::new(list_set.list.len().to_string()).into(),
187                Obj::ClosedRange(cr) => {
188                    if let (Some(a_num), Some(b_num)) = (
189                        self.resolve_obj_to_number_resolved(cr.start.as_ref()),
190                        self.resolve_obj_to_number_resolved(cr.end.as_ref()),
191                    ) {
192                        if let Some(n) = count_closed_range_integer_endpoints(&a_num, &b_num) {
193                            return n.into();
194                        }
195                    }
196                    obj.clone()
197                }
198                Obj::Range(r) => {
199                    if let (Some(a_num), Some(b_num)) = (
200                        self.resolve_obj_to_number_resolved(r.start.as_ref()),
201                        self.resolve_obj_to_number_resolved(r.end.as_ref()),
202                    ) {
203                        if let Some(n) = count_half_open_range_integer_endpoints(&a_num, &b_num) {
204                            return n.into();
205                        }
206                    }
207                    obj.clone()
208                }
209                _ => obj.clone(),
210            },
211            Obj::TupleDim(dim) => match &*dim.arg {
212                Obj::Tuple(tuple) => Number::new(tuple.args.len().to_string()).into(),
213                _ => obj.clone(),
214            },
215            Obj::CartDim(cart_dim) => match &*cart_dim.set {
216                Obj::Cart(cart) => Number::new(cart.args.len().to_string()).into(),
217                _ => obj.clone(),
218            },
219            Obj::Proj(proj) => match &*proj.set {
220                Obj::Cart(cart) => {
221                    let projection_index_number = self.resolve_obj_to_number(&proj.dim);
222                    if let Some(projection_index_number) = projection_index_number {
223                        let projection_index_parsed_result =
224                            projection_index_number.normalized_value.parse::<usize>();
225                        if let Ok(projection_index_one_based) = projection_index_parsed_result {
226                            if projection_index_one_based >= 1
227                                && projection_index_one_based <= cart.args.len()
228                            {
229                                return (*cart.args[projection_index_one_based - 1]).clone();
230                            }
231                        }
232                    }
233                    obj.clone()
234                }
235                _ => {
236                    let known_cart_obj = self.get_object_equal_to_cart(&proj.set.to_string());
237                    if let Some(known_cart_obj) = known_cart_obj {
238                        let projection_index_number = self.resolve_obj_to_number(&proj.dim);
239                        if let Some(projection_index_number) = projection_index_number {
240                            let projection_index_parsed_result =
241                                projection_index_number.normalized_value.parse::<usize>();
242                            if let Ok(projection_index_one_based) = projection_index_parsed_result {
243                                if projection_index_one_based >= 1
244                                    && projection_index_one_based <= known_cart_obj.args.len()
245                                {
246                                    return (*known_cart_obj.args[projection_index_one_based - 1])
247                                        .clone();
248                                }
249                            }
250                        }
251                    }
252                    obj.clone()
253                }
254            },
255            Obj::ObjAtIndex(obj_at_index) => match &*obj_at_index.obj {
256                Obj::Tuple(tuple) => {
257                    let tuple_index_number = self.resolve_obj_to_number(&obj_at_index.index);
258                    if let Some(tuple_index_number) = tuple_index_number {
259                        let tuple_index_parsed_result =
260                            tuple_index_number.normalized_value.parse::<usize>();
261                        if let Ok(tuple_index_one_based) = tuple_index_parsed_result {
262                            if tuple_index_one_based >= 1
263                                && tuple_index_one_based <= tuple.args.len()
264                            {
265                                return (*tuple.args[tuple_index_one_based - 1]).clone();
266                            }
267                        }
268                    }
269                    obj.clone()
270                }
271                Obj::FiniteSeqListObj(list) => {
272                    let ix = self.resolve_obj_to_number(&obj_at_index.index);
273                    if let Some(ix) = ix {
274                        if let Ok(one_based) = ix.normalized_value.parse::<usize>() {
275                            if one_based >= 1 && one_based <= list.objs.len() {
276                                return (*list.objs[one_based - 1]).clone();
277                            }
278                        }
279                    }
280                    obj.clone()
281                }
282                _ => {
283                    let known_tuple_obj =
284                        self.get_obj_equal_to_tuple(&obj_at_index.obj.to_string());
285                    if let Some(known_tuple_obj) = known_tuple_obj {
286                        let tuple_index_number = self.resolve_obj_to_number(&obj_at_index.index);
287                        if let Some(tuple_index_number) = tuple_index_number {
288                            let tuple_index_parsed_result =
289                                tuple_index_number.normalized_value.parse::<usize>();
290                            if let Ok(tuple_index_one_based) = tuple_index_parsed_result {
291                                if tuple_index_one_based >= 1
292                                    && tuple_index_one_based <= known_tuple_obj.args.len()
293                                {
294                                    return (*known_tuple_obj.args[tuple_index_one_based - 1])
295                                        .clone();
296                                }
297                            }
298                        }
299                    }
300                    if let Some(known_list) =
301                        self.get_obj_equal_to_finite_seq_list(&obj_at_index.obj.to_string())
302                    {
303                        let ix = self.resolve_obj_to_number(&obj_at_index.index);
304                        if let Some(ix) = ix {
305                            if let Ok(one_based) = ix.normalized_value.parse::<usize>() {
306                                if one_based >= 1 && one_based <= known_list.objs.len() {
307                                    return (*known_list.objs[one_based - 1]).clone();
308                                }
309                            }
310                        }
311                    }
312                    obj.clone()
313                }
314            },
315            Obj::FamilyObj(f) => {
316                let params: Vec<Obj> = f.params.iter().map(|p| self.resolve_obj(p)).collect();
317                FamilyObj::new(f.name.clone(), params).into()
318            }
319            _ => obj.clone(),
320        }
321    }
322
323    pub(crate) fn obj_is_resolved_zero(&self, obj: &Obj) -> bool {
324        self.resolve_obj_to_number(obj)
325            .map(|n| {
326                matches!(
327                    compare_normalized_number_str_to_zero(&n.normalized_value),
328                    NumberCompareResult::Equal
329                )
330            })
331            .unwrap_or(false)
332    }
333
334    /// If `obj` is `(-1) * u` or `u * (-1)` with literal `-1`, returns `u`.
335    pub(crate) fn peel_mul_by_literal_neg_one(&self, obj: &Obj) -> Option<Obj> {
336        let Obj::Mul(m) = obj else {
337            return None;
338        };
339        if let Some(ln) = self.resolve_obj_to_number(m.left.as_ref()) {
340            if ln.normalized_value == "-1" {
341                return Some(m.right.as_ref().clone());
342            }
343        }
344        if let Some(rn) = self.resolve_obj_to_number(m.right.as_ref()) {
345            if rn.normalized_value == "-1" {
346                return Some(m.left.as_ref().clone());
347            }
348        }
349        None
350    }
351}