Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
198 changes: 198 additions & 0 deletions crates/filament/src/ir_passes/mono/mappings.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
use super::{Base, Underlying};
use fil_ir as ir;
use std::collections::HashMap;
use std::hash::Hash;

/// Generic mapping with debug info and better error messages
pub struct MonoMapping<K, V> {
map: HashMap<K, V>,
name: &'static str,
debug_mode: bool,
}

impl<K, V> MonoMapping<K, V>
where
K: Hash + Eq + Copy,
V: Copy,
{
pub fn new(name: &'static str) -> Self {
Self {
map: HashMap::new(),
name,
debug_mode: std::env::var("FIL_MONO_DEBUG").is_ok(),
}
}

/// Insert a new mapping, warning if overwriting
pub fn insert(&mut self, key: K, value: V) {
if let Some(_old) = self.map.insert(key, value) {
if self.debug_mode {
eprintln!("{}: Overwrote existing mapping", self.name);
}
} else if self.debug_mode {
eprintln!("{}: Added new mapping", self.name);
}
}

/// Get a mapping, panicking with detailed context if not found
pub fn get(&self, key: K) -> V {
*self.map.get(&key).unwrap_or_else(|| {
panic!(
"{}: Missing key. Available keys: {}",
self.name,
self.map.len()
)
})
}

/// Try to get a mapping, returning None if not found
pub fn find(&self, key: K) -> Option<V> {
let result = self.map.get(&key).copied();
if self.debug_mode && result.is_none() {
eprintln!("{}: Key not found", self.name);
}
result
}

/// Check if a key exists
pub fn contains_key(&self, key: K) -> bool {

Check failure on line 58 in crates/filament/src/ir_passes/mono/mappings.rs

View workflow job for this annotation

GitHub Actions / Check Formatting

methods `contains_key`, `len`, `is_empty`, and `clear` are never used
self.map.contains_key(&key)
}

/// Get the number of mappings
pub fn len(&self) -> usize {
self.map.len()
}

/// Check if the mapping is empty
pub fn is_empty(&self) -> bool {
self.map.is_empty()
}

/// Iterate over all mappings
pub fn iter(&self) -> impl Iterator<Item = (&K, &V)> {
self.map.iter()
}

/// Clear all mappings
pub fn clear(&mut self) {
if self.debug_mode && !self.map.is_empty() {
eprintln!("{}: Clearing {} mappings", self.name, self.map.len());
}
self.map.clear();
}
}

impl<K, V> Default for MonoMapping<K, V>
where
K: Hash + Eq + Copy,
V: Copy,
{
fn default() -> Self {
Self::new("default")
}
}

/// Specialized port mapping that handles complex composite keys
pub struct PortMapping {
map: HashMap<

Check failure on line 98 in crates/filament/src/ir_passes/mono/mappings.rs

View workflow job for this annotation

GitHub Actions / Check Formatting

very complex type used. Consider factoring parts into `type` definitions
(Option<Base<ir::Invoke>>, Underlying<ir::Port>),
Base<ir::Port>,
>,
debug_mode: bool,
}

impl PortMapping {
pub fn new() -> Self {
Self {
map: HashMap::new(),
debug_mode: std::env::var("FIL_MONO_DEBUG").is_ok(),
}
}

/// Insert a port mapping
pub fn insert(
&mut self,
inv: Option<Base<ir::Invoke>>,
old_port: Underlying<ir::Port>,
new_port: Base<ir::Port>,
) {
let key = (inv, old_port);
if let Some(_old) = self.map.insert(key, new_port) {
if self.debug_mode {
eprintln!("PortMapping: Overwrote existing port mapping");
}
} else if self.debug_mode {
eprintln!("PortMapping: Added new port mapping");
}
}

/// Get a port mapping, returning None if not found
pub fn get(
&self,
inv: Option<Base<ir::Invoke>>,
old_port: Underlying<ir::Port>,
) -> Option<Base<ir::Port>> {
let key = (inv, old_port);
let result = self.map.get(&key).copied();
if self.debug_mode && result.is_none() {
eprintln!("PortMapping: Port key not found");
}
result
}

/// Get a port mapping, panicking if not found
pub fn expect(
&self,
inv: Option<Base<ir::Invoke>>,
old_port: Underlying<ir::Port>,
) -> Base<ir::Port> {
let key = (inv, old_port);
*self.map.get(&key).unwrap_or_else(|| {
panic!(
"PortMapping: Missing port key. Available keys: {}",
self.map.len()
)
})
}

/// Check if a port mapping exists
pub fn contains_key(

Check failure on line 160 in crates/filament/src/ir_passes/mono/mappings.rs

View workflow job for this annotation

GitHub Actions / Check Formatting

methods `contains_key`, `len`, `is_empty`, and `clear` are never used
&self,
inv: Option<Base<ir::Invoke>>,
old_port: Underlying<ir::Port>,
) -> bool {
self.map.contains_key(&(inv, old_port))
}

/// Get the number of mappings
pub fn len(&self) -> usize {
self.map.len()
}

/// Check if the mapping is empty
pub fn is_empty(&self) -> bool {
self.map.is_empty()
}

/// Clear all mappings
pub fn clear(&mut self) {
if self.debug_mode && !self.map.is_empty() {
eprintln!("PortMapping: Clearing {} mappings", self.map.len());
}
self.map.clear();
}
}

impl Default for PortMapping {
fn default() -> Self {
Self::new()
}
}

/// Type aliases for commonly used mappings
pub type EventMapping = MonoMapping<Underlying<ir::Event>, Base<ir::Event>>;
pub type ParamMapping = MonoMapping<Underlying<ir::Param>, Base<ir::Param>>;
pub type InstanceMapping =
MonoMapping<Underlying<ir::Instance>, Base<ir::Instance>>;
pub type InvokeMapping = MonoMapping<Underlying<ir::Invoke>, Base<ir::Invoke>>;
6 changes: 6 additions & 0 deletions crates/filament/src/ir_passes/mono/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
mod global;
mod mappings;
mod monodeferred;
mod monomorphize;
mod monosig;
mod param_resolver;
mod utils;

pub(super) use global::{CompKey, InstanceInfo};
pub(super) use mappings::{
EventMapping, InstanceMapping, InvokeMapping, ParamMapping, PortMapping,
};
pub(super) use monodeferred::MonoDeferred;
pub(super) use monosig::MonoSig;
pub(super) use param_resolver::ParamResolver;
pub(super) use utils::{
Base, BaseComp, IntoBase, IntoUdl, Underlying, UnderlyingComp,
};
Expand Down
31 changes: 18 additions & 13 deletions crates/filament/src/ir_passes/mono/monodeferred.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ impl MonoDeferred<'_, '_> {

/// The [CompKey] associated with the underlying component being monomorphized.
fn comp_key(&self) -> CompKey {
let binding = self.monosig.binding.inner();
let binding = self.monosig.resolver.inner();
let conc_params = if self.underlying.is_ext() {
vec![]
} else {
Expand Down Expand Up @@ -73,7 +73,7 @@ impl MonoDeferred<'_, '_> {
// Add events without monomorphizing their data. The data is updated after the body is monomorphized
// because it can mention existential parameters.
let new_idx = monosig.base.add(event.clone());
monosig.event_map.insert(idx.ul(), new_idx);
monosig.events.insert(idx.ul(), new_idx);
pass.inst_info_mut(comp_k.clone())
.add_event(idx.ul(), new_idx);
}
Expand Down Expand Up @@ -129,14 +129,19 @@ impl MonoDeferred<'_, '_> {
for (idx, _) in
self.underlying.ports().iter().filter(|(_, p)| p.is_sig())
{
let port_key = (None, idx.ul());
let base = self.monosig.port_map[&port_key];
let base = self.monosig.ports.expect(None, idx.ul());
self.monosig
.port_data(&self.underlying, self.pass, idx.ul(), base);
}

// Handle event delays after monomorphization because delays might mention existential parameters.
for (old, &new) in self.monosig.event_map.clone().iter() {
let events: Vec<_> = self
.monosig
.events
.iter()
.map(|(&old, &new)| (old, new))
.collect();
for (old, new) in events {
self.monosig
.event_delay(&self.underlying, self.pass, old, new);
}
Expand All @@ -147,7 +152,7 @@ impl MonoDeferred<'_, '_> {

/// Add to the parameter binding
pub fn push_binding(&mut self, p: Underlying<ir::Param>, v: u64) {
self.monosig.binding.push(p, v);
self.monosig.resolver.push(p, v);
}

/// Monomorphize a component definition
Expand All @@ -173,7 +178,7 @@ impl MonoDeferred<'_, '_> {
self.underlying.display(param)
)
};
self.monosig.binding.push(param, v);
self.monosig.resolver.push(param, v);
}

// Monomorphize the rest of the signature
Expand Down Expand Up @@ -241,16 +246,16 @@ impl MonoDeferred<'_, '_> {

while i < bound {
let index = index.ul();
let orig_l = self.monosig.binding.len();
self.monosig.binding.push(index, i);
let orig_l = self.monosig.resolver.len();
self.monosig.resolver.push(index, i);
for cmd in body.iter() {
let cmd = self.command(cmd);
self.monosig.base.extend_cmds(cmd);
}
// Remove all the bindings added in this scope including the index
self.monosig
.binding
.pop_n(self.monosig.binding.len() - orig_l);
.resolver
.pop_n(self.monosig.resolver.len() - orig_l);
i += 1;
}
}
Expand Down Expand Up @@ -295,7 +300,7 @@ impl MonoDeferred<'_, '_> {

if !params
.into_iter()
.all(|idx| self.monosig.binding.get(&idx).is_some())
.all(|idx| self.monosig.resolver.get(&idx).is_some())
{
// Discards the assertion if it references parameters that can't be resolved (bundle parameters, etc)
// TODO(edmund): Find a better solution to this - we should resolve bundle assertions when bundles are unrolled.
Expand Down Expand Up @@ -357,7 +362,7 @@ impl MonoDeferred<'_, '_> {
self.monosig.base.comp().display(e)
)
};
self.monosig.binding.push(p, v);
self.monosig.resolver.push(p, v);
None
}
ir::Command::Connect(con) => Some(self.connect(con).into()),
Expand Down
Loading
Loading