cubecl_core/ir/
local_allocator.rsuse std::{
cell::RefCell,
collections::HashMap,
rc::Rc,
sync::atomic::{AtomicU16, Ordering},
};
use crate::prelude::ExpandElement;
use super::{Item, Scope, Variable};
type ScopeRef = Rc<RefCell<Scope>>;
pub trait LocalAllocator {
fn create_local_variable(&self, root: ScopeRef, scope: ScopeRef, item: Item) -> ExpandElement;
fn create_local_binding(&self, root: ScopeRef, scope: ScopeRef, item: Item) -> ExpandElement;
fn create_local_undeclared(&self, root: ScopeRef, scope: ScopeRef, item: Item)
-> ExpandElement;
}
#[derive(Default, Clone)]
pub struct VariablePool {
map: Rc<RefCell<HashMap<Item, Vec<ExpandElement>>>>,
}
impl VariablePool {
pub fn reuse(&self, item: Item) -> Option<ExpandElement> {
let map = self.map.borrow();
let variables = map.get(&item)?;
for variable in variables.iter().rev() {
match variable {
ExpandElement::Managed(var) => {
if Rc::strong_count(var) == 1 {
return Some(variable.clone());
}
}
ExpandElement::Plain(_) => (),
}
}
None
}
pub fn insert(&self, var: ExpandElement) {
let mut map = self.map.borrow_mut();
let item = var.item();
if let Some(variables) = map.get_mut(&item) {
variables.push(var.clone());
} else {
map.insert(var.item(), vec![var.clone()]);
}
}
}
#[derive(Default)]
pub struct ReusingAllocator {
pool: VariablePool,
}
impl LocalAllocator for ReusingAllocator {
fn create_local_variable(&self, root: ScopeRef, scope: ScopeRef, item: Item) -> ExpandElement {
if item.elem.is_atomic() {
let new = scope.borrow_mut().create_local_undeclared(item);
return ExpandElement::Plain(new);
}
if let Some(var) = self.pool.reuse(item) {
return var;
}
let new = ExpandElement::Managed(Rc::new(root.borrow_mut().create_local(item)));
self.pool.insert(new.clone());
new
}
fn create_local_binding(&self, root: ScopeRef, scope: ScopeRef, item: Item) -> ExpandElement {
self.create_local_variable(root, scope, item)
}
fn create_local_undeclared(
&self,
_root: ScopeRef,
scope: ScopeRef,
item: Item,
) -> ExpandElement {
ExpandElement::Plain(scope.borrow_mut().create_local_undeclared(item))
}
}
#[derive(Default)]
pub struct HybridAllocator {
variable_allocator: ReusingAllocator,
ssa_index: AtomicU16,
}
impl LocalAllocator for HybridAllocator {
fn create_local_variable(&self, root: ScopeRef, scope: ScopeRef, item: Item) -> ExpandElement {
self.ssa_index.fetch_add(1, Ordering::AcqRel);
self.variable_allocator
.create_local_variable(root, scope, item)
}
fn create_local_binding(&self, _root: ScopeRef, scope: ScopeRef, item: Item) -> ExpandElement {
let id = self.ssa_index.fetch_add(1, Ordering::AcqRel);
let depth = scope.borrow().depth;
ExpandElement::Plain(Variable::LocalBinding { id, item, depth })
}
fn create_local_undeclared(
&self,
_root: ScopeRef,
scope: ScopeRef,
item: Item,
) -> ExpandElement {
let id = self.ssa_index.fetch_add(1, Ordering::AcqRel);
let depth = scope.borrow().depth;
ExpandElement::Plain(Variable::Local { id, item, depth })
}
}