Skip to main content

veryl_analyzer/conv/
context.rs

1use crate::analyzer_error::{AnalyzerError, ExceedLimitKind};
2use crate::conv::instance::{InstanceHistory, InstanceHistoryError};
3use crate::ir::{
4    Component, Comptime, Declaration, Expression, FfClock, FfReset, FuncPath, Function, Interface,
5    IrResult, ShapeRef, Signature, Type, VarId, VarIndex, VarKind, VarPath, VarSelect, Variable,
6    VariableInfo,
7};
8use crate::namespace::Namespace;
9use crate::namespace_table;
10use crate::symbol::{Affiliation, ClockDomain, Direction, GenericMap, SymbolId};
11use crate::symbol_path::GenericSymbolPath;
12use crate::value::MaskCache;
13use crate::{HashMap, HashSet};
14use std::sync::Arc;
15use veryl_parser::resource_table::StrId;
16use veryl_parser::token_range::TokenRange;
17use veryl_parser::veryl_token::Token;
18
19#[derive(Clone)]
20pub struct Config {
21    pub retain_component_body: bool,
22    pub instance_depth_limit: usize,
23    pub instance_total_limit: usize,
24    pub evaluate_size_limit: usize,
25    pub evaluate_array_limit: usize,
26}
27
28impl Default for Config {
29    fn default() -> Self {
30        Self {
31            retain_component_body: false,
32            instance_depth_limit: 1024,
33            instance_total_limit: 1024 * 1024,
34            evaluate_size_limit: 1024 * 1024,
35            evaluate_array_limit: 128,
36        }
37    }
38}
39
40#[derive(Default)]
41pub struct Context {
42    pub config: Config,
43    pub var_id: VarId,
44    pub var_paths: HashMap<VarPath, (VarId, Comptime)>,
45    pub func_paths: HashMap<FuncPath, VarId>,
46    pub variables: HashMap<VarId, Variable>,
47    pub functions: HashMap<VarId, Function>,
48    pub port_types: HashMap<VarPath, (Type, ClockDomain)>,
49    pub modports: HashMap<StrId, Vec<(StrId, Direction)>>,
50    pub declarations: Vec<Declaration>,
51    pub default_clock: Option<(VarPath, SymbolId)>,
52    pub default_reset: Option<(VarPath, SymbolId)>,
53    pub instance_history: InstanceHistory,
54    pub select_paths: Vec<(VarPath, GenericSymbolPath)>,
55    pub select_dims: Vec<usize>,
56    pub ignore_var_func: bool,
57    pub disalbe_const_opt: bool,
58    pub namespaces: Vec<Namespace>,
59    pub in_generic: bool,
60    pub allow_component_as_factor: bool,
61    pub in_test_module: bool,
62    pub in_global_func: Option<Token>,
63    pub in_if_reset: bool,
64    pub current_clock: Option<Comptime>,
65    pub mask_cache: MaskCache,
66    pub tb_reset_cycles: HashMap<StrId, Expression>,
67    pub tb_clock_period: HashMap<StrId, Expression>,
68    pub tb_reset_clock: HashMap<StrId, StrId>,
69    hierarchy: Vec<StrId>,
70    hierarchical_variables: Vec<Vec<VarPath>>,
71    hierarchical_functions: Vec<Vec<FuncPath>>,
72    shadowed_variables: HashMap<VarPath, Vec<(VarId, Comptime)>>,
73    affiliation: Vec<Affiliation>,
74    overrides: Vec<HashMap<VarPath, (Comptime, Expression)>>,
75    generic_maps: Vec<Vec<GenericMap>>,
76    errors: Vec<AnalyzerError>,
77}
78
79impl Context {
80    pub fn inherit(&mut self, tgt: &mut Context) {
81        std::mem::swap(&mut self.overrides, &mut tgt.overrides);
82        std::mem::swap(&mut self.generic_maps, &mut tgt.generic_maps);
83        std::mem::swap(&mut self.instance_history, &mut tgt.instance_history);
84        std::mem::swap(&mut self.errors, &mut tgt.errors);
85        std::mem::swap(&mut self.namespaces, &mut tgt.namespaces);
86        self.disalbe_const_opt = tgt.disalbe_const_opt;
87        self.in_generic = tgt.in_generic;
88        self.allow_component_as_factor = tgt.allow_component_as_factor;
89        self.config = tgt.config.clone();
90    }
91
92    pub fn get_override(&self, x: &VarPath) -> Option<&(Comptime, Expression)> {
93        let overrides = self.overrides.last()?;
94        overrides.get(x)
95    }
96
97    pub fn get_variable_info(&self, id: VarId) -> Option<VariableInfo> {
98        self.variables.get(&id).map(VariableInfo::new)
99    }
100
101    pub fn resolve_path(&self, mut path: GenericSymbolPath) -> GenericSymbolPath {
102        let Some(namespace) = namespace_table::get(path.paths[0].base.id) else {
103            return path;
104        };
105        path.resolve_imported(&namespace, None);
106        for map in self.generic_maps.iter().rev() {
107            path.apply_map(map);
108        }
109        path
110    }
111
112    pub fn insert_var_path(&mut self, path: VarPath, value: Comptime) -> VarId {
113        let id = self.var_id;
114        self.insert_var_path_with_id(path, id, value);
115        self.var_id.inc();
116        id
117    }
118
119    pub fn insert_var_path_with_id(&mut self, path: VarPath, id: VarId, value: Comptime) {
120        if let Some(x) = self.hierarchical_variables.last_mut() {
121            x.push(path.clone());
122        }
123
124        let shadowed = self.var_paths.insert(path.clone(), (id, value));
125
126        // store variable shadowed by inner-scope variable
127        if let Some(x) = shadowed {
128            self.shadowed_variables
129                .entry(path)
130                .and_modify(|v| v.push(x.clone()))
131                .or_insert(vec![x]);
132        }
133    }
134
135    pub fn insert_func_path(&mut self, path: FuncPath) -> VarId {
136        let id = self.var_id;
137        self.func_paths.insert(path, id);
138        self.var_id.inc();
139        id
140    }
141
142    pub fn insert_variable(&mut self, id: VarId, mut variable: Variable) {
143        if self.ignore_var_func {
144            return;
145        }
146
147        let hier = &self.hierarchy;
148        if !hier.is_empty() {
149            variable.path.add_prelude(hier);
150        }
151        self.variables.insert(id, variable);
152    }
153
154    pub fn insert_port_type(&mut self, path: VarPath, r#type: Type, clock_domain: ClockDomain) {
155        self.port_types.insert(path, (r#type, clock_domain));
156    }
157
158    pub fn insert_function(&mut self, id: VarId, mut function: Function) {
159        if self.ignore_var_func {
160            return;
161        }
162
163        let hier = &self.hierarchy;
164        if !hier.is_empty() {
165            function.path.add_prelude(hier);
166        }
167        self.functions.insert(id, function);
168    }
169
170    pub fn insert_declaration(&mut self, decl: Declaration) {
171        if !decl.is_null() {
172            self.declarations.push(decl);
173        }
174    }
175
176    pub fn insert_error(&mut self, mut error: AnalyzerError) {
177        let mut replaced = false;
178
179        // merge MultipleAssignment which have same identifier
180        if let AnalyzerError::MultipleAssignment {
181            identifier: ref new_ident,
182            error_locations: ref mut new_locations,
183            ..
184        } = error
185        {
186            for e in &mut self.errors {
187                if let AnalyzerError::MultipleAssignment {
188                    identifier: org_ident,
189                    error_locations: org_locations,
190                    ..
191                } = e
192                    && new_ident == org_ident
193                {
194                    org_locations.append(new_locations);
195                    org_locations.sort();
196                    org_locations.dedup();
197                    replaced = true;
198                    break;
199                }
200            }
201        }
202
203        if !replaced && !self.errors.contains(&error) {
204            self.errors.push(error);
205        }
206    }
207
208    pub fn insert_modport(&mut self, name: StrId, members: Vec<(StrId, Direction)>) {
209        self.modports.insert(name, members);
210    }
211
212    pub fn extract_function(&mut self, context: &mut Context, base: &VarPath, array: &ShapeRef) {
213        for (id, mut variable) in context.variables.drain() {
214            variable.path.add_prelude(&base.0);
215            variable.prepend_array(array);
216            self.variables.insert(id, variable);
217        }
218
219        for (mut path, id) in context.func_paths.drain() {
220            if !path.path.starts_with(&base.0) {
221                path.path.add_prelude(&base.0);
222            }
223            self.func_paths.insert(path, id);
224        }
225
226        for (id, mut function) in context.functions.drain() {
227            if !array.is_empty() {
228                let total_array = array.total();
229                let func_body = function.functions.remove(0);
230                if let Some(total_array) = total_array {
231                    for i in 0..total_array {
232                        let var_index = VarIndex::from_index(i, array);
233                        let mut func_body = func_body.clone();
234                        func_body.set_index(&var_index);
235                        function.functions.push(func_body);
236                    }
237                }
238            }
239
240            if !function.path.path.starts_with(&base.0) {
241                function.path.path.add_prelude(&base.0);
242            }
243            self.functions.insert(id, function);
244        }
245    }
246
247    pub fn extract_var_paths(&mut self, context: &Context, base: &VarPath, array: &ShapeRef) {
248        for (path, (id, comptime)) in &context.var_paths {
249            if path.starts_with(&base.0) {
250                let mut path = path.clone();
251                path.remove_prelude(&base.0);
252                if !path.0.is_empty() {
253                    let mut comptime = comptime.clone();
254                    for _ in 0..array.dims() {
255                        comptime.r#type.array.remove(0);
256                    }
257                    self.var_paths.insert(path, (*id, comptime));
258                }
259            }
260        }
261    }
262
263    pub fn extract_interface_member(
264        &mut self,
265        base: StrId,
266        array: &ShapeRef,
267        component: Interface,
268        modport: Option<StrId>,
269        clock_domain: ClockDomain,
270        token: TokenRange,
271    ) {
272        let mut inserted = HashSet::default();
273
274        let modport_members = if let Some(x) = &modport {
275            component.get_modport(x)
276        } else {
277            HashMap::default()
278        };
279
280        let mut id_map = HashMap::default();
281        for mut variable in component.variables.into_values() {
282            if modport.is_some() {
283                if let Some(x) = modport_members.get(&variable.path.first()) {
284                    variable.kind = match x {
285                        Direction::Input => VarKind::Input,
286                        Direction::Output => VarKind::Output,
287                        Direction::Inout => VarKind::Inout,
288                        _ => variable.kind,
289                    };
290                } else {
291                    // Skip non-modport member
292                    continue;
293                }
294            }
295
296            variable.prepend_array(array);
297
298            // override token, affiliation to interface instance
299            variable.token = token;
300            variable.affiliation = self.get_affiliation();
301
302            inserted.insert(variable.path.clone());
303            let comptime = Comptime::from_type(variable.r#type.clone(), clock_domain, token);
304            variable.path.add_prelude(&[base]);
305            let id = self.insert_var_path(variable.path.clone(), comptime);
306
307            // id mapping for struct/union members
308            id_map.insert(variable.id, id);
309
310            variable.id = id;
311            self.insert_variable(id, variable);
312        }
313
314        // import non-variable VarPath
315        for (mut path, (id, mut comptime)) in component.var_paths {
316            if !inserted.contains(&path) {
317                path.add_prelude(&[base]);
318                comptime.r#type.prepend_array(array);
319
320                if let Some(id) = id_map.get(&id) {
321                    self.insert_var_path_with_id(path, *id, comptime);
322                } else {
323                    self.insert_var_path(path, comptime);
324                }
325            }
326        }
327    }
328
329    pub fn inc_select_dim(&mut self) {
330        if let Some(x) = self.select_dims.last_mut() {
331            *x += 1;
332        }
333    }
334
335    pub fn get_select_dim(&self) -> Option<usize> {
336        self.select_dims.last().copied()
337    }
338
339    pub fn set_default_clock(&mut self, path: VarPath, id: SymbolId) {
340        self.default_clock.replace((path, id));
341    }
342
343    pub fn set_default_reset(&mut self, path: VarPath, id: SymbolId) {
344        self.default_reset.replace((path, id));
345    }
346
347    pub fn get_default_clock(&self) -> Option<(FfClock, SymbolId)> {
348        if let Some(x) = &self.default_clock {
349            if let Some((id, comptime)) = &self.var_paths.get(&x.0) {
350                let ret = FfClock {
351                    id: *id,
352                    index: VarIndex::default(),
353                    select: VarSelect::default(),
354                    comptime: comptime.clone(),
355                };
356                Some((ret, x.1))
357            } else {
358                None
359            }
360        } else {
361            None
362        }
363    }
364
365    pub fn get_default_reset(&self) -> Option<(FfReset, SymbolId)> {
366        if let Some(x) = &self.default_reset {
367            if let Some((id, comptime)) = &self.var_paths.get(&x.0) {
368                let ret = FfReset {
369                    id: *id,
370                    index: VarIndex::default(),
371                    select: VarSelect::default(),
372                    comptime: comptime.clone(),
373                };
374                Some((ret, x.1))
375            } else {
376                None
377            }
378        } else {
379            None
380        }
381    }
382
383    pub fn check_size(&mut self, x: usize, token: TokenRange) -> Option<usize> {
384        if x > self.config.evaluate_size_limit {
385            self.insert_error(AnalyzerError::exceed_limit(
386                ExceedLimitKind::EvaluateSize,
387                x,
388                &token,
389            ));
390            None
391        } else {
392            Some(x)
393        }
394    }
395
396    pub fn block<F, T>(&mut self, f: F) -> IrResult<T>
397    where
398        F: FnOnce(&mut Context) -> IrResult<T>,
399    {
400        f(self)
401    }
402
403    pub fn push_instance_history(&mut self, x: Signature) -> Result<bool, InstanceHistoryError> {
404        self.instance_history.push(x, &self.config)
405    }
406
407    pub fn pop_instance_history(&mut self) {
408        self.instance_history.pop();
409    }
410
411    pub fn get_current_signature(&self) -> Option<&Signature> {
412        self.instance_history.get_current_signature()
413    }
414
415    pub fn get_instance_history(&self, sig: &Signature) -> Option<Arc<Component>> {
416        self.instance_history.get(sig)
417    }
418
419    pub fn set_instance_history(&mut self, sig: &Signature, component: Arc<Component>) {
420        self.instance_history.set(sig, component);
421    }
422
423    pub fn push_hierarchy(&mut self, x: StrId) {
424        self.hierarchy.push(x);
425        self.hierarchical_variables.push(vec![]);
426        self.hierarchical_functions.push(vec![]);
427    }
428
429    pub fn pop_hierarchy(&mut self) {
430        self.hierarchy.pop();
431        let drops = self.hierarchical_variables.pop();
432        if let Some(drops) = drops {
433            for x in drops {
434                if let Some(y) = self.shadowed_variables.get_mut(&x)
435                    && let Some(y) = y.pop()
436                {
437                    self.var_paths.insert(x, y);
438                } else {
439                    self.var_paths.remove(&x);
440                }
441            }
442        }
443        let drops = self.hierarchical_functions.pop();
444        if let Some(drops) = drops {
445            for x in drops {
446                self.func_paths.remove(&x);
447            }
448        }
449    }
450
451    pub fn push_affiliation(&mut self, x: Affiliation) {
452        self.affiliation.push(x);
453    }
454
455    pub fn pop_affiliation(&mut self) {
456        self.affiliation.pop();
457    }
458
459    pub fn push_override(&mut self, x: HashMap<VarPath, (Comptime, Expression)>) {
460        self.overrides.push(x);
461    }
462
463    pub fn pop_override(&mut self) {
464        self.overrides.pop();
465    }
466
467    pub fn push_generic_map(&mut self, x: Vec<GenericMap>) {
468        self.generic_maps.push(x);
469    }
470
471    pub fn pop_generic_map(&mut self) {
472        self.generic_maps.pop();
473    }
474
475    pub fn is_affiliated(&self, value: Affiliation) -> bool {
476        if let Some(x) = self.affiliation.last() {
477            *x == value
478        } else {
479            false
480        }
481    }
482
483    pub fn get_affiliation(&self) -> Affiliation {
484        self.affiliation.last().copied().unwrap()
485    }
486
487    pub fn push_namespace(&mut self, namespace: Namespace) {
488        self.namespaces.push(namespace);
489    }
490
491    pub fn pop_namespace(&mut self) {
492        self.namespaces.pop();
493    }
494
495    pub fn current_namespace(&self) -> Option<Namespace> {
496        self.namespaces.last().cloned()
497    }
498
499    pub fn find_path(&self, path: &VarPath) -> Option<(VarId, Comptime)> {
500        self.var_paths.get(path).cloned()
501    }
502
503    pub fn get_variable(&self, id: &VarId) -> Option<Variable> {
504        self.variables.get(id).cloned()
505    }
506
507    pub fn remove_path(&mut self, path: &VarPath) {
508        self.var_paths.remove(path);
509    }
510
511    pub fn drain_var_paths(&mut self) -> HashMap<VarPath, (VarId, Comptime)> {
512        self.var_paths.drain().collect()
513    }
514
515    pub fn drain_func_paths(&mut self) -> HashMap<FuncPath, VarId> {
516        self.func_paths.drain().collect()
517    }
518
519    pub fn drain_variables(&mut self) -> HashMap<VarId, Variable> {
520        self.variables.drain().collect()
521    }
522
523    pub fn drain_port_types(&mut self) -> HashMap<VarPath, (Type, ClockDomain)> {
524        self.port_types.drain().collect()
525    }
526
527    pub fn drain_functions(&mut self) -> HashMap<VarId, Function> {
528        self.functions.drain().collect()
529    }
530
531    pub fn drain_modports(&mut self) -> HashMap<StrId, Vec<(StrId, Direction)>> {
532        self.modports.drain().collect()
533    }
534
535    pub fn drain_declarations(&mut self) -> Vec<Declaration> {
536        self.declarations.drain(..).collect()
537    }
538
539    pub fn drain_errors(&mut self) -> Vec<AnalyzerError> {
540        self.errors.drain(..).collect()
541    }
542}