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