1use std::{
2 collections::BTreeMap,
3 sync::{Arc, RwLock},
4};
5
6use color_eyre::eyre::anyhow;
7use itertools::Itertools;
8use rustc_hash::FxHashMap as HashMap;
9use serde::{Deserialize, Serialize};
10use spade_ast_lowering::id_tracker::{ExprIdTracker, ImplIdTracker};
11use spade_common::location_info::WithLocation;
12use spade_common::name::NameID;
13use spade_hir::{
14 query::QueryCache,
15 symbol_table::{FrozenSymtab, SymbolTable},
16 ItemList,
17};
18use spade_hir_lowering::{
19 name_map::{NameSource, NamedValue},
20 NameSourceMap,
21};
22use spade_mir::{
23 renaming::{VerilogNameMap, VerilogNameSource},
24 unit_name::InstanceMap,
25};
26use spade_typeinference::{
27 equation::TypedExpression, traits::TraitImplList, HasType, OwnedTypeState, SharedTypeState,
28 TypeState,
29};
30use spade_types::ConcreteType;
31
32use spade_common::sizes::{add_field, SerializedSize};
33
34#[derive(Serialize, Deserialize)]
35pub struct StoredMirContext {
36 pub type_state: OwnedTypeState,
38 pub reg_name_map: BTreeMap<NameID, NameID>,
39 pub verilog_name_map: VerilogNameMap,
40}
41
42impl StoredMirContext {
43 fn with_shared(self, shared: Arc<SharedTypeState>) -> MirContext {
44 MirContext {
45 type_state: TypeState {
46 owned: self.type_state,
47 shared,
48 },
49 reg_name_map: self.reg_name_map,
50 verilog_name_map: self.verilog_name_map,
51 }
52 }
53}
54
55impl SerializedSize for StoredMirContext {
56 fn accumulate_size(
57 &self,
58 field: &[&'static str],
59 into: &mut HashMap<Vec<&'static str>, usize>,
60 ) {
61 let Self {
62 type_state,
63 reg_name_map,
64 verilog_name_map,
65 } = self;
66
67 let mut ts_path = field.to_vec();
68 ts_path.push("type_state");
69 type_state.accumulate_size(&ts_path, into);
70
71 add_field(field, "type_state", type_state, into);
72 add_field(field, "reg_name_map", reg_name_map, into);
73 add_field(field, "verilog_name_map", verilog_name_map, into);
74 }
75}
76
77pub struct MirContext {
78 pub type_state: TypeState,
80 pub reg_name_map: BTreeMap<NameID, NameID>,
81 pub verilog_name_map: VerilogNameMap,
82}
83
84impl MirContext {
85 fn to_stored(self) -> StoredMirContext {
86 StoredMirContext {
87 type_state: self.type_state.owned,
88 reg_name_map: self.reg_name_map,
89 verilog_name_map: self.verilog_name_map,
90 }
91 }
92}
93
94#[derive(Serialize, Deserialize)]
96pub struct StoredCompilerState {
97 pub code: Vec<(String, String)>,
99 pub symtab: FrozenSymtab,
100 pub idtracker: Arc<ExprIdTracker>,
101 pub impl_idtracker: ImplIdTracker,
102 pub item_list: ItemList,
103 pub name_source_map: Arc<RwLock<NameSourceMap>>,
104 pub instance_map: InstanceMap,
105 pub mir_context: HashMap<NameID, StoredMirContext>,
106 pub shared_type_state: Arc<SharedTypeState>,
107 pub trait_impl_list: TraitImplList,
108}
109
110impl StoredCompilerState {
111 pub fn into_compiler_state(self) -> CompilerState {
112 let Self {
113 code,
114 symtab,
115 idtracker,
116 impl_idtracker,
117 item_list,
118 name_source_map,
119 instance_map,
120 mir_context,
121 shared_type_state,
122 trait_impl_list,
123 } = self;
124
125 CompilerState {
126 code,
127 symtab,
128 idtracker,
129 impl_idtracker,
130 item_list,
131 name_source_map,
132 instance_map,
133 mir_context: mir_context
134 .into_iter()
135 .map(|(k, v)| (k, v.with_shared(Arc::clone(&shared_type_state))))
136 .collect(),
137 shared_type_state,
138 trait_impl_list,
139 }
140 }
141}
142
143pub struct CompilerState {
144 pub code: Vec<(String, String)>,
146 pub symtab: FrozenSymtab,
147 pub idtracker: Arc<ExprIdTracker>,
148 pub impl_idtracker: ImplIdTracker,
149 pub item_list: ItemList,
150 pub name_source_map: Arc<RwLock<NameSourceMap>>,
151 pub instance_map: InstanceMap,
152 pub mir_context: HashMap<NameID, MirContext>,
153 pub shared_type_state: Arc<SharedTypeState>,
154 pub trait_impl_list: TraitImplList,
155}
156
157impl CompilerState {
158 pub fn into_stored(self) -> StoredCompilerState {
159 StoredCompilerState {
160 code: self.code,
161 symtab: self.symtab,
162 idtracker: self.idtracker,
163 impl_idtracker: self.impl_idtracker,
164 item_list: self.item_list,
165 name_source_map: self.name_source_map,
166 instance_map: self.instance_map,
167 mir_context: self
168 .mir_context
169 .into_iter()
170 .map(|(k, v)| (k, v.to_stored()))
171 .collect(),
172 shared_type_state: self.shared_type_state,
173 trait_impl_list: self.trait_impl_list,
174 }
175 }
176
177 pub fn build_query_cache<'a>(&'a self) -> QueryCache {
178 QueryCache::from_item_list(&self.item_list)
179 }
180
181 pub fn demangle_string(&self, mangled: &str) -> Option<String> {
183 let string_map = self
187 .name_source_map
188 .read()
189 .unwrap()
190 .inner
191 .iter()
192 .flat_map(|(k, v)| {
193 vec![
194 (k.var_name(), v.clone()),
195 (k.backward_var_name(), v.clone()),
196 ]
197 })
198 .collect::<HashMap<_, _>>();
199
200 string_map.get(mangled).map(|name| match name {
201 NamedValue::Primary(source) => self.demangle_name_source(source),
202 NamedValue::Secondary(source, description) => {
203 format!("{} ({description})", self.demangle_name_source(source))
204 }
205 })
206 }
207
208 pub fn demangle_name_source(&self, source: &NameSource) -> String {
209 match source {
210 NameSource::Name(n) => format!("{n}"),
211 NameSource::Expr(e) => {
212 format!(
213 "(id) {}",
214 &self.code[e.file_id].1[e.span.start().to_usize()..e.span.end().to_usize()]
215 )
216 }
217 }
218 }
219
220 pub fn name_source_of_hierarchical_value(
221 &self,
222 top_module: &NameID,
223 hierarchy: &[String],
224 query_cache: &QueryCache,
225 ) -> color_eyre::Result<Option<NameSource>> {
226 let (verilog_source, _mir_ctx) = source_of_hierarchical_value(
227 top_module,
228 hierarchy,
229 &self.instance_map,
230 &self.mir_context,
231 )?;
232
233 match verilog_source {
234 VerilogNameSource::ForwardName(n) | VerilogNameSource::BackwardName(n) => {
235 Ok(Some(NameSource::Name(n.clone().nowhere())))
236 }
237 VerilogNameSource::ForwardExpr(id) | VerilogNameSource::BackwardExpr(id) => {
238 Ok(query_cache
239 .id_to_expression(*id)
240 .map(|loc_expr| NameSource::Expr(loc_expr.map_ref(|_| *id))))
241 }
242 }
243 }
244
245 pub fn type_of_hierarchical_value(
246 &self,
247 top_module: &NameID,
248 hierarchy: &[String],
249 ) -> color_eyre::Result<ConcreteType> {
250 type_of_hierarchical_value(
251 top_module,
252 hierarchy,
253 &self.instance_map,
254 &self.mir_context,
255 self.symtab.symtab(),
256 &self.item_list,
257 )
258 }
259}
260
261impl SerializedSize for StoredCompilerState {
262 fn accumulate_size(
263 &self,
264 field: &[&'static str],
265 into: &mut HashMap<Vec<&'static str>, usize>,
266 ) {
267 let Self {
268 code,
269 symtab,
270 idtracker,
271 impl_idtracker,
272 item_list,
273 name_source_map,
274 instance_map,
275 mir_context,
276 shared_type_state,
277 trait_impl_list,
278 } = self;
279
280 for (_, mc) in mir_context {
281 let mut path = field.to_vec();
282 path.push("mir_context");
283 mc.accumulate_size(&path, into);
284 }
285
286 add_field(field, "code", code, into);
287 add_field(field, "symtab", symtab, into);
288 add_field(field, "idtracker", idtracker, into);
289 add_field(field, "impl_idtracker", impl_idtracker, into);
290 add_field(field, "item_list", item_list, into);
291 add_field(field, "name_source_map", name_source_map, into);
292 add_field(field, "instance_map", instance_map, into);
293 add_field(field, "mir_context", mir_context, into);
294 add_field(field, "shared_type_state", shared_type_state, into);
295 add_field(field, "trait_impl_list", trait_impl_list, into);
296 }
297}
298
299pub fn source_of_hierarchical_value<'a>(
300 top_module: &'a NameID,
301 hierarchy: &'a [String],
302 instance_map: &'a InstanceMap,
303 mir_contexts: &'a HashMap<NameID, MirContext>,
304) -> color_eyre::Result<(&'a VerilogNameSource, &'a MirContext)> {
305 let mut hierarchy = Vec::from(hierarchy);
306 let value_name = hierarchy.pop().unwrap();
307 hierarchy.reverse();
308
309 let mut current_unit = top_module;
311 let mut path_so_far = vec![format!("{}", top_module)];
312 while let Some(next_instance_name) = hierarchy.pop() {
313 let local_map = instance_map
314 .inner
315 .get(¤t_unit.clone())
316 .ok_or_else(|| {
317 let candidates = instance_map
318 .inner
319 .keys()
320 .map(|n| format!(" {n}"))
321 .collect::<Vec<_>>();
322
323 let candidates_msg = if candidates.is_empty() {
324 String::new()
325 } else {
326 format!(" candidates\n {}", candidates.join(" \n"))
327 };
328
329 anyhow!(
330 "Did not find a unit named {} in {}\n{candidates_msg}",
331 &next_instance_name,
332 path_so_far.join(".")
333 )
334 })?;
335 let next = local_map.get(&next_instance_name);
336 if let Some(next) = next {
337 current_unit = next;
338 } else {
339 let candidates_msg = if local_map.is_empty() {
340 String::new()
341 } else {
342 format!("\n candidates:\n {}", local_map.keys().join(" \n"))
343 };
344
345 return Err(anyhow!(
346 "{} has no spade unit instance named {next_instance_name}{candidates_msg}",
347 path_so_far.join(".")
348 ));
349 };
350 path_so_far.push(next_instance_name.to_string());
351 }
352
353 let mir_ctx = mir_contexts
355 .get(current_unit)
356 .ok_or_else(|| anyhow!("Did not find information a unit named {current_unit}"))?;
357
358 let source = mir_ctx
359 .verilog_name_map
360 .lookup_name(&value_name)
361 .ok_or_else(|| {
362 anyhow!(
363 "Did not find spade variable for verilog identifier '{value_name}' in '{path}'",
364 path = path_so_far.join(".")
365 )
366 })?;
367
368 Ok((source, mir_ctx))
369}
370
371pub fn type_of_hierarchical_value(
372 top_module: &NameID,
373 hierarchy: &[String],
374 instance_map: &InstanceMap,
375 mir_contexts: &HashMap<NameID, MirContext>,
376 symtab: &SymbolTable,
377 item_list: &ItemList,
378) -> color_eyre::Result<ConcreteType> {
379 let (source, mir_ctx) =
380 source_of_hierarchical_value(top_module, hierarchy, instance_map, mir_contexts)?;
381
382 let typed_expr = match source {
383 VerilogNameSource::ForwardName(n) => TypedExpression::Name(n.clone()),
384 VerilogNameSource::ForwardExpr(id) => TypedExpression::Id(*id),
385 VerilogNameSource::BackwardName(_) | VerilogNameSource::BackwardExpr(_) => {
386 return Err(anyhow!("Translation of backward port types is unsupported"))
387 }
388 };
389
390 let ty = typed_expr
391 .try_get_type(&mir_ctx.type_state)
392 .ok_or_else(|| anyhow!("Did not find a type for {}", typed_expr))?;
393
394 let concrete = mir_ctx
395 .type_state
396 .ungenerify_type(&ty, symtab, &item_list.types)
397 .ok_or_else(|| {
398 anyhow!(
399 "Tried to ungenerify generic type {ty}",
400 ty = ty.display(&mir_ctx.type_state)
401 )
402 })?;
403
404 Ok(concrete)
405}