vyre_foundation/ir_inner/model/
arena.rs1#![allow(unsafe_code)]
3
4use crate::ir_inner::model::expr::Expr;
5use crate::ir_inner::model::program::BufferDecl;
6use bumpalo::Bump;
7use rustc_hash::FxHashMap;
8use std::cell::{Cell, UnsafeCell};
9use std::sync::Arc;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
13pub struct ExprRef {
14 index: usize,
15}
16
17impl ExprRef {
18 #[must_use]
20 #[inline]
21 pub fn index(self) -> usize {
22 self.index
23 }
24}
25
26#[derive(Default)]
32pub struct ExprArena {
33 bump: Bump,
34 exprs: UnsafeCell<Vec<*const Expr>>,
35 len: Cell<usize>,
36}
37
38impl ExprArena {
39 #[must_use]
41 #[inline]
42 pub fn new() -> Self {
43 Self::default()
44 }
45
46 #[must_use]
48 pub fn alloc(&self, expr: Expr) -> ExprRef {
49 let index = self.len.get();
50 let ptr = std::ptr::from_ref::<Expr>(self.bump.alloc(expr));
51 unsafe {
53 (*self.exprs.get()).push(ptr);
54 }
55 self.len.set(index + 1);
56 ExprRef { index }
57 }
58
59 #[must_use]
61 pub fn get(&self, expr_ref: ExprRef) -> Option<&Expr> {
62 unsafe {
65 let vec: &Vec<*const Expr> = &*self.exprs.get();
66 vec.get(expr_ref.index).and_then(|ptr| ptr.as_ref())
67 }
68 }
69
70 pub fn reset(&mut self) {
72 unsafe {
75 let vec = self.exprs.get_mut();
76 for &ptr in vec.iter() {
77 std::ptr::drop_in_place(ptr as *mut Expr);
78 }
79 vec.clear();
80 }
81 self.len.set(0);
82 self.bump.reset();
83 }
84
85 #[must_use]
87 #[inline]
88 pub fn len(&self) -> usize {
89 self.len.get()
90 }
91
92 #[must_use]
94 #[inline]
95 pub fn is_empty(&self) -> bool {
96 self.len() == 0
97 }
98}
99
100impl Drop for ExprArena {
101 fn drop(&mut self) {
102 unsafe {
105 let vec = self.exprs.get_mut();
106 for &ptr in vec.iter() {
107 std::ptr::drop_in_place(ptr as *mut Expr);
108 }
109 }
110 }
111}
112
113pub struct ArenaProgram<'a> {
115 arena: &'a ExprArena,
116 buffers: Vec<BufferDecl>,
117 buffer_index: FxHashMap<Arc<str>, usize>,
118 workgroup_size: [u32; 3],
119 entry: Vec<ExprRef>,
120}
121
122impl<'a> ArenaProgram<'a> {
123 pub(crate) fn new(
124 arena: &'a ExprArena,
125 buffers: Vec<BufferDecl>,
126 workgroup_size: [u32; 3],
127 ) -> Self {
128 let mut buffer_index = FxHashMap::default();
129 buffer_index.reserve(buffers.len());
130 for (index, buffer) in buffers.iter().enumerate() {
131 buffer_index
132 .entry(Arc::clone(&buffer.name))
133 .or_insert(index);
134 }
135 Self {
136 arena,
137 buffers,
138 buffer_index,
139 workgroup_size,
140 entry: Vec::new(),
141 }
142 }
143
144 #[must_use]
146 pub fn push_expr(&mut self, expr: Expr) -> ExprRef {
147 let expr_ref = self.arena.alloc(expr);
148 self.entry.push(expr_ref);
149 expr_ref
150 }
151
152 #[must_use]
154 pub fn expr(&self, expr_ref: ExprRef) -> Option<&Expr> {
155 self.arena.get(expr_ref)
156 }
157
158 #[must_use]
160 pub fn buffers(&self) -> &[BufferDecl] {
161 &self.buffers
162 }
163
164 #[must_use]
166 pub fn buffer(&self, name: &str) -> Option<&BufferDecl> {
167 self.buffer_index
168 .get(name)
169 .and_then(|&index| self.buffers.get(index))
170 }
171
172 #[must_use]
174 pub fn workgroup_size(&self) -> [u32; 3] {
175 self.workgroup_size
176 }
177
178 #[must_use]
180 pub fn entry(&self) -> &[ExprRef] {
181 &self.entry
182 }
183}
184
185#[cfg(test)]
186mod tests {
187 use super::{ArenaProgram, ExprArena};
188 use crate::ir_inner::model::expr::Expr;
189 use crate::ir_inner::model::program::BufferDecl;
190 use crate::ir_inner::model::types::DataType;
191
192 #[test]
193 fn arena_allocates_stable_expression_refs() {
194 let arena = ExprArena::new();
195 let first = arena.alloc(Expr::u32(7));
196 let second = arena.alloc(Expr::var("x"));
197 assert_eq!(first.index(), 0);
198 assert_eq!(second.index(), 1);
199 assert_eq!(arena.get(first), Some(&Expr::u32(7)));
200 assert_eq!(arena.get(second), Some(&Expr::var("x")));
201 }
202
203 #[test]
204 fn arena_program_keeps_buffers_and_expression_handles() {
205 let arena = ExprArena::new();
206 let mut program = ArenaProgram::new(
207 &arena,
208 vec![BufferDecl::read("input", 0, DataType::U32)],
209 [64, 1, 1],
210 );
211 let expr_ref = program.push_expr(Expr::load("input", Expr::u32(0)));
212 assert_eq!(program.entry(), &[expr_ref]);
213 assert_eq!(program.buffer("input").map(BufferDecl::binding), Some(0));
214 assert_eq!(
215 program.expr(expr_ref),
216 Some(&Expr::load("input", Expr::u32(0)))
217 );
218 }
219}